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.
5 *
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.
14 *
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.
26 *
27 */
28
29 /*
30 * Konstantin Dimitrov's thanks list:
31 *
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.
37 *
38 */
39
40 #ifdef HAVE_KERNEL_OPTION_HEADERS
41 #include "opt_snd.h"
42 #endif
43
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>
48
49 #include <dev/pci/pcireg.h>
50 #include <dev/pci/pcivar.h>
51
52 #include "mixer_if.h"
53
54 SND_DECLARE_FILE("$FreeBSD: stable/9/sys/dev/sound/pci/envy24ht.c 254306 2013-08-13 22:05:50Z scottl $");
55
56 static MALLOC_DEFINE(M_ENVY24HT, "envy24ht", "envy24ht audio");
57
58 /* -------------------------------------------------------------------- */
59
60 struct sc_info;
61
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
67
68 #define ENVY24HT_TIMEOUT 1000
69
70 #define ENVY24HT_DEFAULT_FORMAT SND_FORMAT(AFMT_S16_LE, 2, 0)
71
72 #define ENVY24HT_NAMELEN 32
73
74 struct envy24ht_sample {
75 volatile u_int32_t buffer;
76 };
77
78 typedef struct envy24ht_sample sample32_t;
79
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 */
87
88 /* channel information */
89 u_int32_t format;
90 u_int32_t speed;
91 u_int32_t blk; /* hw block size(dword) */
92
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 *);
99
100 /* flags */
101 int run;
102 };
103
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);
112 };
113
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;
123 };
124
125 /* device private data */
126 struct sc_info {
127 device_t dev;
128 struct mtx *lock;
129
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;
146
147 /* system configuration data */
148 struct cfg_info *cfg;
149
150 /* ADC/DAC number and info */
151 int adcn, dacn;
152 void *adc[4], *dac[4];
153
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];
158
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
166 /* current status */
167 u_int32_t speed;
168 int run[2];
169 u_int16_t intr[2];
170 struct pcmchan_caps caps[2];
171
172 /* channel info table */
173 unsigned chnum;
174 struct sc_chinfo chan[11];
175 };
176
177 /* -------------------------------------------------------------------- */
178
179 /*
180 * prototypes
181 */
182
183 /* DMA emulator */
184 static void envy24ht_p8u(struct sc_chinfo *);
185 static void envy24ht_p16sl(struct sc_chinfo *);
186 static void envy24ht_p32sl(struct sc_chinfo *);
187 static void envy24ht_r16sl(struct sc_chinfo *);
188 static void envy24ht_r32sl(struct sc_chinfo *);
189
190 /* channel interface */
191 static void *envy24htchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
192 static int envy24htchan_setformat(kobj_t, void *, u_int32_t);
193 static u_int32_t envy24htchan_setspeed(kobj_t, void *, u_int32_t);
194 static u_int32_t envy24htchan_setblocksize(kobj_t, void *, u_int32_t);
195 static int envy24htchan_trigger(kobj_t, void *, int);
196 static u_int32_t envy24htchan_getptr(kobj_t, void *);
197 static struct pcmchan_caps *envy24htchan_getcaps(kobj_t, void *);
198
199 /* mixer interface */
200 static int envy24htmixer_init(struct snd_mixer *);
201 static int envy24htmixer_reinit(struct snd_mixer *);
202 static int envy24htmixer_uninit(struct snd_mixer *);
203 static int envy24htmixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
204 static u_int32_t envy24htmixer_setrecsrc(struct snd_mixer *, u_int32_t);
205
206 /* SPI codec access interface */
207 static void *envy24ht_spi_create(device_t, void *, int, int);
208 static void envy24ht_spi_destroy(void *);
209 static void envy24ht_spi_init(void *);
210 static void envy24ht_spi_reinit(void *);
211 static void envy24ht_spi_setvolume(void *, int, unsigned int, unsigned int);
212
213 /* -------------------------------------------------------------------- */
214
215 /*
216 system constant tables
217 */
218
219 /* API -> hardware channel map */
220 static unsigned envy24ht_chanmap[ENVY24HT_CHAN_NUM] = {
221 ENVY24HT_CHAN_PLAY_DAC1, /* 1 */
222 ENVY24HT_CHAN_PLAY_DAC2, /* 2 */
223 ENVY24HT_CHAN_PLAY_DAC3, /* 3 */
224 ENVY24HT_CHAN_PLAY_DAC4, /* 4 */
225 ENVY24HT_CHAN_PLAY_SPDIF, /* 0 */
226 ENVY24HT_CHAN_REC_MIX, /* 5 */
227 ENVY24HT_CHAN_REC_SPDIF, /* 6 */
228 ENVY24HT_CHAN_REC_ADC1, /* 7 */
229 ENVY24HT_CHAN_REC_ADC2, /* 8 */
230 ENVY24HT_CHAN_REC_ADC3, /* 9 */
231 ENVY24HT_CHAN_REC_ADC4, /* 10 */
232 };
233
234 /* mixer -> API channel map. see above */
235 static int envy24ht_mixmap[] = {
236 -1, /* Master output level. It is depend on codec support */
237 -1, /* Treble level of all output channels */
238 -1, /* Bass level of all output channels */
239 -1, /* Volume of synthesier input */
240 0, /* Output level for the audio device */
241 -1, /* Output level for the PC speaker */
242 7, /* line in jack */
243 -1, /* microphone jack */
244 -1, /* CD audio input */
245 -1, /* Recording monitor */
246 1, /* alternative codec */
247 -1, /* global recording level */
248 -1, /* Input gain */
249 -1, /* Output gain */
250 8, /* Input source 1 */
251 9, /* Input source 2 */
252 10, /* Input source 3 */
253 6, /* Digital (input) 1 */
254 -1, /* Digital (input) 2 */
255 -1, /* Digital (input) 3 */
256 -1, /* Phone input */
257 -1, /* Phone output */
258 -1, /* Video/TV (audio) in */
259 -1, /* Radio in */
260 -1, /* Monitor volume */
261 };
262
263 /* variable rate audio */
264 static u_int32_t envy24ht_speed[] = {
265 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
266 12000, 11025, 9600, 8000, 0
267 };
268
269 /* known boards configuration */
270 static struct codec_entry spi_codec = {
271 envy24ht_spi_create,
272 envy24ht_spi_destroy,
273 envy24ht_spi_init,
274 envy24ht_spi_reinit,
275 envy24ht_spi_setvolume,
276 NULL, /* setrate */
277 };
278
279 static struct cfg_info cfg_table[] = {
280 {
281 "Envy24HT audio (Terratec Aureon 7.1 Space)",
282 0x153b, 0x1145,
283 0x0b, 0x80, 0xfc, 0xc3,
284 0x21efff, 0x7fffff, 0x5e1000,
285 0x40000, 0x80000, 0x1000, 0x00, 0x02,
286 0,
287 &spi_codec,
288 },
289 {
290 "Envy24HT audio (Terratec Aureon 5.1 Sky)",
291 0x153b, 0x1147,
292 0x0a, 0x80, 0xfc, 0xc3,
293 0x21efff, 0x7fffff, 0x5e1000,
294 0x40000, 0x80000, 0x1000, 0x00, 0x02,
295 0,
296 &spi_codec,
297 },
298 {
299 "Envy24HT audio (Terratec Aureon 7.1 Universe)",
300 0x153b, 0x1153,
301 0x0b, 0x80, 0xfc, 0xc3,
302 0x21efff, 0x7fffff, 0x5e1000,
303 0x40000, 0x80000, 0x1000, 0x00, 0x02,
304 0,
305 &spi_codec,
306 },
307 {
308 "Envy24HT audio (AudioTrak Prodigy 7.1)",
309 0x4933, 0x4553,
310 0x0b, 0x80, 0xfc, 0xc3,
311 0x21efff, 0x7fffff, 0x5e1000,
312 0x40000, 0x80000, 0x1000, 0x00, 0x02,
313 0,
314 &spi_codec,
315 },
316 {
317 "Envy24HT audio (Terratec PHASE 28)",
318 0x153b, 0x1149,
319 0x0b, 0x80, 0xfc, 0xc3,
320 0x21efff, 0x7fffff, 0x5e1000,
321 0x40000, 0x80000, 0x1000, 0x00, 0x02,
322 0,
323 &spi_codec,
324 },
325 {
326 "Envy24HT-S audio (Terratec PHASE 22)",
327 0x153b, 0x1150,
328 0x10, 0x80, 0xf0, 0xc3,
329 0x7ffbc7, 0x7fffff, 0x438,
330 0x10, 0x20, 0x400, 0x01, 0x00,
331 0,
332 &spi_codec,
333 },
334 {
335 "Envy24HT audio (AudioTrak Prodigy 7.1 LT)",
336 0x3132, 0x4154,
337 0x4b, 0x80, 0xfc, 0xc3,
338 0x7ff8ff, 0x7fffff, 0x700,
339 0x400, 0x200, 0x100, 0x00, 0x02,
340 0,
341 &spi_codec,
342 },
343 {
344 "Envy24HT audio (AudioTrak Prodigy 7.1 XT)",
345 0x3136, 0x4154,
346 0x4b, 0x80, 0xfc, 0xc3,
347 0x7ff8ff, 0x7fffff, 0x700,
348 0x400, 0x200, 0x100, 0x00, 0x02,
349 0,
350 &spi_codec,
351 },
352 {
353 "Envy24HT audio (M-Audio Revolution 7.1)",
354 0x1412, 0x3630,
355 0x43, 0x80, 0xf8, 0xc1,
356 0x3fff85, 0x400072, 0x4000fa,
357 0x08, 0x02, 0x20, 0x00, 0x04,
358 0,
359 &spi_codec,
360 },
361 {
362 "Envy24GT audio (M-Audio Revolution 5.1)",
363 0x1412, 0x3631,
364 0x42, 0x80, 0xf8, 0xc1,
365 0x3fff05, 0x4000f0, 0x4000fa,
366 0x08, 0x02, 0x10, 0x00, 0x03,
367 0,
368 &spi_codec,
369 },
370 {
371 "Envy24HT audio (M-Audio Audiophile 192)",
372 0x1412, 0x3632,
373 0x68, 0x80, 0xf8, 0xc3,
374 0x45, 0x4000b5, 0x7fffba,
375 0x08, 0x02, 0x10, 0x00, 0x03,
376 0,
377 &spi_codec,
378 },
379 {
380 "Envy24HT audio (AudioTrak Prodigy HD2)",
381 0x3137, 0x4154,
382 0x68, 0x80, 0x78, 0xc3,
383 0xfff8ff, 0x200700, 0xdfffff,
384 0x400, 0x200, 0x100, 0x00, 0x05,
385 0,
386 &spi_codec,
387 },
388 {
389 "Envy24HT audio (ESI Juli@)",
390 0x3031, 0x4553,
391 0x20, 0x80, 0xf8, 0xc3,
392 0x7fff9f, 0x8016, 0x7fff9f,
393 0x08, 0x02, 0x10, 0x00, 0x03,
394 0,
395 &spi_codec,
396 },
397 {
398 "Envy24HT-S audio (Terrasoniq TS22PCI)",
399 0x153b, 0x117b,
400 0x10, 0x80, 0xf0, 0xc3,
401 0x7ffbc7, 0x7fffff, 0x438,
402 0x10, 0x20, 0x400, 0x01, 0x00,
403 0,
404 &spi_codec,
405 },
406 {
407 "Envy24HT audio (Generic)",
408 0, 0,
409 0x0b, 0x80, 0xfc, 0xc3,
410 0x21efff, 0x7fffff, 0x5e1000,
411 0x40000, 0x80000, 0x1000, 0x00, 0x02,
412 0,
413 &spi_codec, /* default codec routines */
414 }
415 };
416
417 static u_int32_t envy24ht_recfmt[] = {
418 SND_FORMAT(AFMT_S16_LE, 2, 0),
419 SND_FORMAT(AFMT_S32_LE, 2, 0),
420 0
421 };
422 static struct pcmchan_caps envy24ht_reccaps = {8000, 96000, envy24ht_recfmt, 0};
423
424 static u_int32_t envy24ht_playfmt[] = {
425 SND_FORMAT(AFMT_U8, 2, 0),
426 SND_FORMAT(AFMT_S16_LE, 2, 0),
427 SND_FORMAT(AFMT_S32_LE, 2, 0),
428 0
429 };
430
431 static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0};
432
433 struct envy24ht_emldma {
434 u_int32_t format;
435 void (*emldma)(struct sc_chinfo *);
436 int unit;
437 };
438
439 static struct envy24ht_emldma envy24ht_pemltab[] = {
440 {SND_FORMAT(AFMT_U8, 2, 0), envy24ht_p8u, 2},
441 {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_p16sl, 4},
442 {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_p32sl, 8},
443 {0, NULL, 0}
444 };
445
446 static struct envy24ht_emldma envy24ht_remltab[] = {
447 {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_r16sl, 4},
448 {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_r32sl, 8},
449 {0, NULL, 0}
450 };
451
452 /* -------------------------------------------------------------------- */
453
454 /* common routines */
455 static u_int32_t
envy24ht_rdcs(struct sc_info * sc,int regno,int size)456 envy24ht_rdcs(struct sc_info *sc, int regno, int size)
457 {
458 switch (size) {
459 case 1:
460 return bus_space_read_1(sc->cst, sc->csh, regno);
461 case 2:
462 return bus_space_read_2(sc->cst, sc->csh, regno);
463 case 4:
464 return bus_space_read_4(sc->cst, sc->csh, regno);
465 default:
466 return 0xffffffff;
467 }
468 }
469
470 static void
envy24ht_wrcs(struct sc_info * sc,int regno,u_int32_t data,int size)471 envy24ht_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
472 {
473 switch (size) {
474 case 1:
475 bus_space_write_1(sc->cst, sc->csh, regno, data);
476 break;
477 case 2:
478 bus_space_write_2(sc->cst, sc->csh, regno, data);
479 break;
480 case 4:
481 bus_space_write_4(sc->cst, sc->csh, regno, data);
482 break;
483 }
484 }
485
486 static u_int32_t
envy24ht_rdmt(struct sc_info * sc,int regno,int size)487 envy24ht_rdmt(struct sc_info *sc, int regno, int size)
488 {
489 switch (size) {
490 case 1:
491 return bus_space_read_1(sc->mtt, sc->mth, regno);
492 case 2:
493 return bus_space_read_2(sc->mtt, sc->mth, regno);
494 case 4:
495 return bus_space_read_4(sc->mtt, sc->mth, regno);
496 default:
497 return 0xffffffff;
498 }
499 }
500
501 static void
envy24ht_wrmt(struct sc_info * sc,int regno,u_int32_t data,int size)502 envy24ht_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
503 {
504 switch (size) {
505 case 1:
506 bus_space_write_1(sc->mtt, sc->mth, regno, data);
507 break;
508 case 2:
509 bus_space_write_2(sc->mtt, sc->mth, regno, data);
510 break;
511 case 4:
512 bus_space_write_4(sc->mtt, sc->mth, regno, data);
513 break;
514 }
515 }
516
517 /* -------------------------------------------------------------------- */
518
519 /* I2C port/E2PROM access routines */
520
521 static int
envy24ht_rdi2c(struct sc_info * sc,u_int32_t dev,u_int32_t addr)522 envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
523 {
524 u_int32_t data;
525 int i;
526
527 #if(0)
528 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
529 #endif
530 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
531 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
532 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
533 break;
534 DELAY(32); /* 31.25kHz */
535 }
536 if (i == ENVY24HT_TIMEOUT) {
537 return -1;
538 }
539 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
540 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
541 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_RD, 1);
542 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
543 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
544 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
545 break;
546 DELAY(32); /* 31.25kHz */
547 }
548 if (i == ENVY24HT_TIMEOUT) {
549 return -1;
550 }
551 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CDATA, 1);
552
553 #if(0)
554 device_printf(sc->dev, "envy24ht_rdi2c(): return 0x%x\n", data);
555 #endif
556 return (int)data;
557 }
558
559 static int
envy24ht_wri2c(struct sc_info * sc,u_int32_t dev,u_int32_t addr,u_int32_t data)560 envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
561 {
562 u_int32_t tmp;
563 int i;
564
565 #if(0)
566 device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
567 #endif
568 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
569 tmp = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
570 if ((tmp & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
571 break;
572 DELAY(32); /* 31.25kHz */
573 }
574 if (i == ENVY24HT_TIMEOUT) {
575 return -1;
576 }
577 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
578 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDATA, data, 1);
579 envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
580 (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_WR, 1);
581 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
582 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
583 if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
584 break;
585 DELAY(32); /* 31.25kHz */
586 }
587 if (i == ENVY24HT_TIMEOUT) {
588 return -1;
589 }
590
591 return 0;
592 }
593
594 static int
envy24ht_rdrom(struct sc_info * sc,u_int32_t addr)595 envy24ht_rdrom(struct sc_info *sc, u_int32_t addr)
596 {
597 u_int32_t data;
598
599 #if(0)
600 device_printf(sc->dev, "envy24ht_rdrom(sc, 0x%02x)\n", addr);
601 #endif
602 data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
603 if ((data & ENVY24HT_CCS_I2CSTAT_ROM) == 0) {
604 #if(0)
605 device_printf(sc->dev, "envy24ht_rdrom(): E2PROM not presented\n");
606 #endif
607 return -1;
608 }
609
610 return envy24ht_rdi2c(sc, ENVY24HT_CCS_I2CDEV_ROM, addr);
611 }
612
613 static struct cfg_info *
envy24ht_rom2cfg(struct sc_info * sc)614 envy24ht_rom2cfg(struct sc_info *sc)
615 {
616 struct cfg_info *buff;
617 int size;
618 int i;
619
620 #if(0)
621 device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n");
622 #endif
623 size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE);
624 if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) {
625 #if(0)
626 device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size);
627 #endif
628 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
629 if (buff == NULL) {
630 #if(0)
631 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
632 #endif
633 return NULL;
634 }
635 buff->free = 1;
636
637 /* no valid e2prom, using default values */
638 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
639 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
640 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
641 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
642 buff->scfg = 0x0b;
643 buff->acl = 0x80;
644 buff->i2s = 0xfc;
645 buff->spdif = 0xc3;
646 buff->gpiomask = 0x21efff;
647 buff->gpiostate = 0x7fffff;
648 buff->gpiodir = 0x5e1000;
649 buff->cdti = 0x40000;
650 buff->cclk = 0x80000;
651 buff->cs = 0x1000;
652 buff->cif = 0x00;
653 buff->type = 0x02;
654
655 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0;
656 i++)
657 if (cfg_table[i].subvendor == buff->subvendor &&
658 cfg_table[i].subdevice == buff->subdevice)
659 break;
660 buff->name = cfg_table[i].name;
661 buff->codec = cfg_table[i].codec;
662
663 return buff;
664 #if 0
665 return NULL;
666 #endif
667 }
668 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
669 if (buff == NULL) {
670 #if(0)
671 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
672 #endif
673 return NULL;
674 }
675 buff->free = 1;
676
677 buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
678 buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
679 buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
680 buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
681 buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG);
682 buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL);
683 buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S);
684 buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF);
685 buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \
686 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \
687 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16;
688 buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \
689 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \
690 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16;
691 buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \
692 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \
693 envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16;
694
695 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
696 if (cfg_table[i].subvendor == buff->subvendor &&
697 cfg_table[i].subdevice == buff->subdevice)
698 break;
699 buff->name = cfg_table[i].name;
700 buff->codec = cfg_table[i].codec;
701
702 return buff;
703 }
704
705 static void
envy24ht_cfgfree(struct cfg_info * cfg)706 envy24ht_cfgfree(struct cfg_info *cfg) {
707 if (cfg == NULL)
708 return;
709 if (cfg->free)
710 free(cfg, M_ENVY24HT);
711 return;
712 }
713
714 /* -------------------------------------------------------------------- */
715
716 /* AC'97 codec access routines */
717
718 #if 0
719 static int
envy24ht_coldcd(struct sc_info * sc)720 envy24ht_coldcd(struct sc_info *sc)
721 {
722 u_int32_t data;
723 int i;
724
725 #if(0)
726 device_printf(sc->dev, "envy24ht_coldcd()\n");
727 #endif
728 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1);
729 DELAY(10);
730 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
731 DELAY(1000);
732 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
733 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
734 if (data & ENVY24HT_MT_AC97CMD_RDY) {
735 return 0;
736 }
737 }
738
739 return -1;
740 }
741
742 static int
envy24ht_slavecd(struct sc_info * sc)743 envy24ht_slavecd(struct sc_info *sc)
744 {
745 u_int32_t data;
746 int i;
747
748 #if(0)
749 device_printf(sc->dev, "envy24ht_slavecd()\n");
750 #endif
751 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD,
752 ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1);
753 DELAY(10);
754 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
755 DELAY(1000);
756 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
757 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
758 if (data & ENVY24HT_MT_AC97CMD_RDY) {
759 return 0;
760 }
761 }
762
763 return -1;
764 }
765
766 static int
envy24ht_rdcd(kobj_t obj,void * devinfo,int regno)767 envy24ht_rdcd(kobj_t obj, void *devinfo, int regno)
768 {
769 struct sc_info *sc = (struct sc_info *)devinfo;
770 u_int32_t data;
771 int i;
772
773 #if(0)
774 device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno);
775 #endif
776 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
777 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1);
778 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
779 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
780 if ((data & ENVY24HT_MT_AC97CMD_RD) == 0)
781 break;
782 }
783 data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2);
784
785 #if(0)
786 device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data);
787 #endif
788 return (int)data;
789 }
790
791 static int
envy24ht_wrcd(kobj_t obj,void * devinfo,int regno,u_int16_t data)792 envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
793 {
794 struct sc_info *sc = (struct sc_info *)devinfo;
795 u_int32_t cmd;
796 int i;
797
798 #if(0)
799 device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
800 #endif
801 envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
802 envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2);
803 envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1);
804 for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
805 cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
806 if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0)
807 break;
808 }
809
810 return 0;
811 }
812
813 static kobj_method_t envy24ht_ac97_methods[] = {
814 KOBJMETHOD(ac97_read, envy24ht_rdcd),
815 KOBJMETHOD(ac97_write, envy24ht_wrcd),
816 KOBJMETHOD_END
817 };
818 AC97_DECLARE(envy24ht_ac97);
819 #endif
820
821 /* -------------------------------------------------------------------- */
822
823 /* GPIO access routines */
824
825 static u_int32_t
envy24ht_gpiord(struct sc_info * sc)826 envy24ht_gpiord(struct sc_info *sc)
827 {
828 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
829 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2);
830 else
831 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2));
832 }
833
834 static void
envy24ht_gpiowr(struct sc_info * sc,u_int32_t data)835 envy24ht_gpiowr(struct sc_info *sc, u_int32_t data)
836 {
837 #if(0)
838 device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF);
839 return;
840 #endif
841 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2);
842 if (sc->cfg->subdevice != 0x1150)
843 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1);
844 return;
845 }
846
847 #if 0
848 static u_int32_t
envy24ht_gpiogetmask(struct sc_info * sc)849 envy24ht_gpiogetmask(struct sc_info *sc)
850 {
851 return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2));
852 }
853 #endif
854
855 static void
envy24ht_gpiosetmask(struct sc_info * sc,u_int32_t mask)856 envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask)
857 {
858 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2);
859 if (sc->cfg->subdevice != 0x1150)
860 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1);
861 return;
862 }
863
864 #if 0
865 static u_int32_t
envy24ht_gpiogetdir(struct sc_info * sc)866 envy24ht_gpiogetdir(struct sc_info *sc)
867 {
868 return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4);
869 }
870 #endif
871
872 static void
envy24ht_gpiosetdir(struct sc_info * sc,u_int32_t dir)873 envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir)
874 {
875 if (sc->cfg->subvendor == 0x153b && sc->cfg->subdevice == 0x1150)
876 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2);
877 else
878 envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4);
879 return;
880 }
881
882 /* -------------------------------------------------------------------- */
883
884 /* SPI codec access interface routine */
885
886 struct envy24ht_spi_codec {
887 struct spicds_info *info;
888 struct sc_info *parent;
889 int dir;
890 int num;
891 int cs, cclk, cdti;
892 };
893
894 static void
envy24ht_spi_ctl(void * codec,unsigned int cs,unsigned int cclk,unsigned int cdti)895 envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
896 {
897 u_int32_t data = 0;
898 struct envy24ht_spi_codec *ptr = codec;
899
900 #if(0)
901 device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
902 #endif
903 data = envy24ht_gpiord(ptr->parent);
904 data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
905 if (cs) data += ptr->cs;
906 if (cclk) data += ptr->cclk;
907 if (cdti) data += ptr->cdti;
908 envy24ht_gpiowr(ptr->parent, data);
909 return;
910 }
911
912 static void *
envy24ht_spi_create(device_t dev,void * info,int dir,int num)913 envy24ht_spi_create(device_t dev, void *info, int dir, int num)
914 {
915 struct sc_info *sc = info;
916 struct envy24ht_spi_codec *buff = NULL;
917
918 #if(0)
919 device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num);
920 #endif
921
922 buff = malloc(sizeof(*buff), M_ENVY24HT, M_NOWAIT);
923 if (buff == NULL)
924 return NULL;
925
926 if (dir == PCMDIR_REC && sc->adc[num] != NULL)
927 buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info;
928 else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
929 buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info;
930 else
931 buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl);
932 if (buff->info == NULL) {
933 free(buff, M_ENVY24HT);
934 return NULL;
935 }
936
937 buff->parent = sc;
938 buff->dir = dir;
939 buff->num = num;
940
941 return (void *)buff;
942 }
943
944 static void
envy24ht_spi_destroy(void * codec)945 envy24ht_spi_destroy(void *codec)
946 {
947 struct envy24ht_spi_codec *ptr = codec;
948 if (ptr == NULL)
949 return;
950 #if(0)
951 device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n");
952 #endif
953
954 if (ptr->dir == PCMDIR_PLAY) {
955 if (ptr->parent->dac[ptr->num] != NULL)
956 spicds_destroy(ptr->info);
957 }
958 else {
959 if (ptr->parent->adc[ptr->num] != NULL)
960 spicds_destroy(ptr->info);
961 }
962
963 free(codec, M_ENVY24HT);
964 }
965
966 static void
envy24ht_spi_init(void * codec)967 envy24ht_spi_init(void *codec)
968 {
969 struct envy24ht_spi_codec *ptr = codec;
970 if (ptr == NULL)
971 return;
972 #if(0)
973 device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n");
974 #endif
975 ptr->cs = ptr->parent->cfg->cs;
976 ptr->cclk = ptr->parent->cfg->cclk;
977 ptr->cdti = ptr->parent->cfg->cdti;
978 spicds_settype(ptr->info, ptr->parent->cfg->type);
979 spicds_setcif(ptr->info, ptr->parent->cfg->cif);
980 if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \
981 ptr->parent->cfg->type == SPICDS_TYPE_AK4528) {
982 spicds_setformat(ptr->info,
983 AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
984 spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
985 }
986
987 /* for the time being, init only first codec */
988 if (ptr->num == 0)
989 spicds_init(ptr->info);
990 }
991
992 static void
envy24ht_spi_reinit(void * codec)993 envy24ht_spi_reinit(void *codec)
994 {
995 struct envy24ht_spi_codec *ptr = codec;
996 if (ptr == NULL)
997 return;
998 #if(0)
999 device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n");
1000 #endif
1001
1002 spicds_reinit(ptr->info);
1003 }
1004
1005 static void
envy24ht_spi_setvolume(void * codec,int dir,unsigned int left,unsigned int right)1006 envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
1007 {
1008 struct envy24ht_spi_codec *ptr = codec;
1009 if (ptr == NULL)
1010 return;
1011 #if(0)
1012 device_printf(ptr->parent->dev, "envy24ht_spi_set()\n");
1013 #endif
1014
1015 spicds_set(ptr->info, dir, left, right);
1016 }
1017
1018 /* -------------------------------------------------------------------- */
1019
1020 /* hardware access routeines */
1021
1022 static struct {
1023 u_int32_t speed;
1024 u_int32_t code;
1025 } envy24ht_speedtab[] = {
1026 {48000, ENVY24HT_MT_RATE_48000},
1027 {24000, ENVY24HT_MT_RATE_24000},
1028 {12000, ENVY24HT_MT_RATE_12000},
1029 {9600, ENVY24HT_MT_RATE_9600},
1030 {32000, ENVY24HT_MT_RATE_32000},
1031 {16000, ENVY24HT_MT_RATE_16000},
1032 {8000, ENVY24HT_MT_RATE_8000},
1033 {96000, ENVY24HT_MT_RATE_96000},
1034 {192000, ENVY24HT_MT_RATE_192000},
1035 {64000, ENVY24HT_MT_RATE_64000},
1036 {44100, ENVY24HT_MT_RATE_44100},
1037 {22050, ENVY24HT_MT_RATE_22050},
1038 {11025, ENVY24HT_MT_RATE_11025},
1039 {88200, ENVY24HT_MT_RATE_88200},
1040 {176400, ENVY24HT_MT_RATE_176400},
1041 {0, 0x10}
1042 };
1043
1044 static u_int32_t
envy24ht_setspeed(struct sc_info * sc,u_int32_t speed)1045 envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) {
1046 u_int32_t code, i2sfmt;
1047 int i = 0;
1048
1049 #if(0)
1050 device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed);
1051 if (speed == 0) {
1052 code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */
1053 envy24ht_slavecd(sc);
1054 }
1055 else {
1056 #endif
1057 for (i = 0; envy24ht_speedtab[i].speed != 0; i++) {
1058 if (envy24ht_speedtab[i].speed == speed)
1059 break;
1060 }
1061 code = envy24ht_speedtab[i].code;
1062 #if 0
1063 }
1064 device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code);
1065 #endif
1066 if (code < 0x10) {
1067 envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1);
1068 if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \
1069 (code == ENVY24HT_MT_RATE_176400)) {
1070 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1071 i2sfmt |= ENVY24HT_MT_I2S_MLR128;
1072 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1073 }
1074 else {
1075 i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
1076 i2sfmt &= ~ENVY24HT_MT_I2S_MLR128;
1077 envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
1078 }
1079 code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1);
1080 code &= ENVY24HT_MT_RATE_MASK;
1081 for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) {
1082 if (envy24ht_speedtab[i].code == code)
1083 break;
1084 }
1085 speed = envy24ht_speedtab[i].speed;
1086 }
1087 else
1088 speed = 0;
1089
1090 #if(0)
1091 device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed);
1092 #endif
1093 return speed;
1094 }
1095
1096 static void
envy24ht_setvolume(struct sc_info * sc,unsigned ch)1097 envy24ht_setvolume(struct sc_info *sc, unsigned ch)
1098 {
1099 #if(0)
1100 device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch);
1101 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1102 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1103 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1104 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1105 #endif
1106 }
1107
1108 static void
envy24ht_mutevolume(struct sc_info * sc,unsigned ch)1109 envy24ht_mutevolume(struct sc_info *sc, unsigned ch)
1110 {
1111 #if 0
1112 u_int32_t vol;
1113
1114 device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch);
1115 vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE;
1116 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
1117 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1118 envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
1119 envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
1120 #endif
1121 }
1122
1123 static u_int32_t
envy24ht_gethwptr(struct sc_info * sc,int dir)1124 envy24ht_gethwptr(struct sc_info *sc, int dir)
1125 {
1126 int unit, regno;
1127 u_int32_t ptr, rtn;
1128
1129 #if(0)
1130 device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir);
1131 #endif
1132 if (dir == PCMDIR_PLAY) {
1133 rtn = sc->psize / 4;
1134 unit = ENVY24HT_PLAY_BUFUNIT / 4;
1135 regno = ENVY24HT_MT_PCNT;
1136 }
1137 else {
1138 rtn = sc->rsize / 4;
1139 unit = ENVY24HT_REC_BUFUNIT / 4;
1140 regno = ENVY24HT_MT_RCNT;
1141 }
1142
1143 ptr = envy24ht_rdmt(sc, regno, 2);
1144 rtn -= (ptr + 1);
1145 rtn /= unit;
1146
1147 #if(0)
1148 device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn);
1149 #endif
1150 return rtn;
1151 }
1152
1153 static void
envy24ht_updintr(struct sc_info * sc,int dir)1154 envy24ht_updintr(struct sc_info *sc, int dir)
1155 {
1156 int regptr, regintr;
1157 u_int32_t mask, intr;
1158 u_int32_t ptr, size, cnt;
1159 u_int16_t blk;
1160
1161 #if(0)
1162 device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir);
1163 #endif
1164 if (dir == PCMDIR_PLAY) {
1165 blk = sc->blk[0];
1166 size = sc->psize / 4;
1167 regptr = ENVY24HT_MT_PCNT;
1168 regintr = ENVY24HT_MT_PTERM;
1169 mask = ~ENVY24HT_MT_INT_PMASK;
1170 }
1171 else {
1172 blk = sc->blk[1];
1173 size = sc->rsize / 4;
1174 regptr = ENVY24HT_MT_RCNT;
1175 regintr = ENVY24HT_MT_RTERM;
1176 mask = ~ENVY24HT_MT_INT_RMASK;
1177 }
1178
1179 ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1;
1180 /*
1181 cnt = blk - ptr % blk - 1;
1182 if (cnt == 0)
1183 cnt = blk - 1;
1184 */
1185 cnt = blk - 1;
1186 #if(0)
1187 device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1188 #endif
1189 envy24ht_wrmt(sc, regintr, cnt, 2);
1190 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1191 #if(0)
1192 device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1193 #endif
1194 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
1195 #if(0)
1196 device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
1197 envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
1198 #endif
1199
1200 return;
1201 }
1202
1203 #if 0
1204 static void
envy24ht_maskintr(struct sc_info * sc,int dir)1205 envy24ht_maskintr(struct sc_info *sc, int dir)
1206 {
1207 u_int32_t mask, intr;
1208
1209 #if(0)
1210 device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
1211 #endif
1212 if (dir == PCMDIR_PLAY)
1213 mask = ENVY24HT_MT_INT_PMASK;
1214 else
1215 mask = ENVY24HT_MT_INT_RMASK;
1216 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
1217 envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
1218
1219 return;
1220 }
1221 #endif
1222
1223 static int
envy24ht_checkintr(struct sc_info * sc,int dir)1224 envy24ht_checkintr(struct sc_info *sc, int dir)
1225 {
1226 u_int32_t mask, stat, intr, rtn;
1227
1228 #if(0)
1229 device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
1230 #endif
1231 intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
1232 if (dir == PCMDIR_PLAY) {
1233 if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
1234 mask = ~ENVY24HT_MT_INT_RSTAT;
1235 envy24ht_wrmt(sc, 0x1a, 0x01, 1);
1236 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);
1237 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1238 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
1239 }
1240 }
1241 else {
1242 if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
1243 mask = ~ENVY24HT_MT_INT_PSTAT;
1244 #if 0
1245 stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
1246 #endif
1247 envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
1248 stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1249 envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
1250 }
1251 }
1252
1253 return rtn;
1254 }
1255
1256 static void
envy24ht_start(struct sc_info * sc,int dir)1257 envy24ht_start(struct sc_info *sc, int dir)
1258 {
1259 u_int32_t stat, sw;
1260
1261 #if(0)
1262 device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
1263 #endif
1264 if (dir == PCMDIR_PLAY)
1265 sw = ENVY24HT_MT_PCTL_PSTART;
1266 else
1267 sw = ENVY24HT_MT_PCTL_RSTART;
1268
1269 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1270 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
1271 #if(0)
1272 DELAY(100);
1273 device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
1274 device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
1275 #endif
1276
1277 return;
1278 }
1279
1280 static void
envy24ht_stop(struct sc_info * sc,int dir)1281 envy24ht_stop(struct sc_info *sc, int dir)
1282 {
1283 u_int32_t stat, sw;
1284
1285 #if(0)
1286 device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir);
1287 #endif
1288 if (dir == PCMDIR_PLAY)
1289 sw = ~ENVY24HT_MT_PCTL_PSTART;
1290 else
1291 sw = ~ENVY24HT_MT_PCTL_RSTART;
1292
1293 stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1294 envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1);
1295
1296 return;
1297 }
1298
1299 #if 0
1300 static int
envy24ht_route(struct sc_info * sc,int dac,int class,int adc,int rev)1301 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1302 {
1303 return 0;
1304 }
1305 #endif
1306
1307 /* -------------------------------------------------------------------- */
1308
1309 /* buffer copy routines */
1310 static void
envy24ht_p32sl(struct sc_chinfo * ch)1311 envy24ht_p32sl(struct sc_chinfo *ch)
1312 {
1313 int length;
1314 sample32_t *dmabuf;
1315 u_int32_t *data;
1316 int src, dst, ssize, dsize, slot;
1317 int i;
1318
1319 length = sndbuf_getready(ch->buffer) / 8;
1320 dmabuf = ch->parent->pbuf;
1321 data = (u_int32_t *)ch->data;
1322 src = sndbuf_getreadyptr(ch->buffer) / 4;
1323 dst = src / 2 + ch->offset;
1324 ssize = ch->size / 4;
1325 dsize = ch->size / 8;
1326 slot = ch->num * 2;
1327
1328 for (i = 0; i < length; i++) {
1329 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
1330 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1331 dst++;
1332 dst %= dsize;
1333 src += 2;
1334 src %= ssize;
1335 }
1336
1337 return;
1338 }
1339
1340 static void
envy24ht_p16sl(struct sc_chinfo * ch)1341 envy24ht_p16sl(struct sc_chinfo *ch)
1342 {
1343 int length;
1344 sample32_t *dmabuf;
1345 u_int16_t *data;
1346 int src, dst, ssize, dsize, slot;
1347 int i;
1348
1349 #if(0)
1350 device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
1351 #endif
1352 length = sndbuf_getready(ch->buffer) / 4;
1353 dmabuf = ch->parent->pbuf;
1354 data = (u_int16_t *)ch->data;
1355 src = sndbuf_getreadyptr(ch->buffer) / 2;
1356 dst = src / 2 + ch->offset;
1357 ssize = ch->size / 2;
1358 dsize = ch->size / 4;
1359 slot = ch->num * 2;
1360 #if(0)
1361 device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1362 #endif
1363
1364 for (i = 0; i < length; i++) {
1365 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1366 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1367 #if(0)
1368 if (i < 16) {
1369 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
1370 printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
1371 }
1372 #endif
1373 dst++;
1374 dst %= dsize;
1375 src += 2;
1376 src %= ssize;
1377 }
1378 #if(0)
1379 printf("\n");
1380 #endif
1381
1382 return;
1383 }
1384
1385 static void
envy24ht_p8u(struct sc_chinfo * ch)1386 envy24ht_p8u(struct sc_chinfo *ch)
1387 {
1388 int length;
1389 sample32_t *dmabuf;
1390 u_int8_t *data;
1391 int src, dst, ssize, dsize, slot;
1392 int i;
1393
1394 length = sndbuf_getready(ch->buffer) / 2;
1395 dmabuf = ch->parent->pbuf;
1396 data = (u_int8_t *)ch->data;
1397 src = sndbuf_getreadyptr(ch->buffer);
1398 dst = src / 2 + ch->offset;
1399 ssize = ch->size;
1400 dsize = ch->size / 4;
1401 slot = ch->num * 2;
1402
1403 for (i = 0; i < length; i++) {
1404 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1405 dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1406 dst++;
1407 dst %= dsize;
1408 src += 2;
1409 src %= ssize;
1410 }
1411
1412 return;
1413 }
1414
1415 static void
envy24ht_r32sl(struct sc_chinfo * ch)1416 envy24ht_r32sl(struct sc_chinfo *ch)
1417 {
1418 int length;
1419 sample32_t *dmabuf;
1420 u_int32_t *data;
1421 int src, dst, ssize, dsize, slot;
1422 int i;
1423
1424 length = sndbuf_getfree(ch->buffer) / 8;
1425 dmabuf = ch->parent->rbuf;
1426 data = (u_int32_t *)ch->data;
1427 dst = sndbuf_getfreeptr(ch->buffer) / 4;
1428 src = dst / 2 + ch->offset;
1429 dsize = ch->size / 4;
1430 ssize = ch->size / 8;
1431 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1432
1433 for (i = 0; i < length; i++) {
1434 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1435 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1436 dst += 2;
1437 dst %= dsize;
1438 src++;
1439 src %= ssize;
1440 }
1441
1442 return;
1443 }
1444
1445 static void
envy24ht_r16sl(struct sc_chinfo * ch)1446 envy24ht_r16sl(struct sc_chinfo *ch)
1447 {
1448 int length;
1449 sample32_t *dmabuf;
1450 u_int16_t *data;
1451 int src, dst, ssize, dsize, slot;
1452 int i;
1453
1454 length = sndbuf_getfree(ch->buffer) / 4;
1455 dmabuf = ch->parent->rbuf;
1456 data = (u_int16_t *)ch->data;
1457 dst = sndbuf_getfreeptr(ch->buffer) / 2;
1458 src = dst / 2 + ch->offset;
1459 dsize = ch->size / 2;
1460 ssize = ch->size / 8;
1461 slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1462
1463 for (i = 0; i < length; i++) {
1464 data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1465 data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1466 dst += 2;
1467 dst %= dsize;
1468 src++;
1469 src %= ssize;
1470 }
1471
1472 return;
1473 }
1474
1475 /* -------------------------------------------------------------------- */
1476
1477 /* channel interface */
1478 static void *
envy24htchan_init(kobj_t obj,void * devinfo,struct snd_dbuf * b,struct pcm_channel * c,int dir)1479 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1480 {
1481 struct sc_info *sc = (struct sc_info *)devinfo;
1482 struct sc_chinfo *ch;
1483 unsigned num;
1484
1485 #if(0)
1486 device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
1487 #endif
1488 snd_mtxlock(sc->lock);
1489 #if 0
1490 if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1491 (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1492 snd_mtxunlock(sc->lock);
1493 return NULL;
1494 }
1495 #endif
1496 num = sc->chnum;
1497
1498 ch = &sc->chan[num];
1499 ch->size = 8 * ENVY24HT_SAMPLE_NUM;
1500 ch->data = malloc(ch->size, M_ENVY24HT, M_NOWAIT);
1501 if (ch->data == NULL) {
1502 ch->size = 0;
1503 ch = NULL;
1504 }
1505 else {
1506 ch->buffer = b;
1507 ch->channel = c;
1508 ch->parent = sc;
1509 ch->dir = dir;
1510 /* set channel map */
1511 ch->num = envy24ht_chanmap[num];
1512 snd_mtxunlock(sc->lock);
1513 sndbuf_setup(ch->buffer, ch->data, ch->size);
1514 snd_mtxlock(sc->lock);
1515 /* these 2 values are dummy */
1516 ch->unit = 4;
1517 ch->blk = 10240;
1518 }
1519 snd_mtxunlock(sc->lock);
1520
1521 return ch;
1522 }
1523
1524 static int
envy24htchan_free(kobj_t obj,void * data)1525 envy24htchan_free(kobj_t obj, void *data)
1526 {
1527 struct sc_chinfo *ch = data;
1528 struct sc_info *sc = ch->parent;
1529
1530 #if(0)
1531 device_printf(sc->dev, "envy24htchan_free()\n");
1532 #endif
1533 snd_mtxlock(sc->lock);
1534 if (ch->data != NULL) {
1535 free(ch->data, M_ENVY24HT);
1536 ch->data = NULL;
1537 }
1538 snd_mtxunlock(sc->lock);
1539
1540 return 0;
1541 }
1542
1543 static int
envy24htchan_setformat(kobj_t obj,void * data,u_int32_t format)1544 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
1545 {
1546 struct sc_chinfo *ch = data;
1547 struct sc_info *sc = ch->parent;
1548 struct envy24ht_emldma *emltab;
1549 /* unsigned int bcnt, bsize; */
1550 int i;
1551
1552 #if(0)
1553 device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
1554 #endif
1555 snd_mtxlock(sc->lock);
1556 /* check and get format related information */
1557 if (ch->dir == PCMDIR_PLAY)
1558 emltab = envy24ht_pemltab;
1559 else
1560 emltab = envy24ht_remltab;
1561 if (emltab == NULL) {
1562 snd_mtxunlock(sc->lock);
1563 return -1;
1564 }
1565 for (i = 0; emltab[i].format != 0; i++)
1566 if (emltab[i].format == format)
1567 break;
1568 if (emltab[i].format == 0) {
1569 snd_mtxunlock(sc->lock);
1570 return -1;
1571 }
1572
1573 /* set format information */
1574 ch->format = format;
1575 ch->emldma = emltab[i].emldma;
1576 if (ch->unit > emltab[i].unit)
1577 ch->blk *= ch->unit / emltab[i].unit;
1578 else
1579 ch->blk /= emltab[i].unit / ch->unit;
1580 ch->unit = emltab[i].unit;
1581
1582 /* set channel buffer information */
1583 ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
1584 #if 0
1585 if (ch->dir == PCMDIR_PLAY)
1586 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1587 else
1588 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1589 bsize *= ch->unit;
1590 bcnt = ch->size / bsize;
1591 sndbuf_resize(ch->buffer, bcnt, bsize);
1592 #endif
1593 snd_mtxunlock(sc->lock);
1594
1595 #if(0)
1596 device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
1597 #endif
1598 return 0;
1599 }
1600
1601 /*
1602 IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1603 of speed information value. And real hardware speed setting is done
1604 at start triggered(see envy24htchan_trigger()). So, at this function
1605 is called, any value that ENVY24 can use is able to set. But, at
1606 start triggerd, some other channel is running, and that channel's
1607 speed isn't same with, then trigger function will fail.
1608 */
1609 static u_int32_t
envy24htchan_setspeed(kobj_t obj,void * data,u_int32_t speed)1610 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1611 {
1612 struct sc_chinfo *ch = data;
1613 u_int32_t val, prev;
1614 int i;
1615
1616 #if(0)
1617 device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
1618 #endif
1619 prev = 0x7fffffff;
1620 for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
1621 if (abs(val - speed) < abs(prev - speed))
1622 prev = val;
1623 else
1624 break;
1625 }
1626 ch->speed = prev;
1627
1628 #if(0)
1629 device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
1630 #endif
1631 return ch->speed;
1632 }
1633
1634 static u_int32_t
envy24htchan_setblocksize(kobj_t obj,void * data,u_int32_t blocksize)1635 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1636 {
1637 struct sc_chinfo *ch = data;
1638 /* struct sc_info *sc = ch->parent; */
1639 u_int32_t size, prev;
1640 unsigned int bcnt, bsize;
1641
1642 #if(0)
1643 device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
1644 #endif
1645 prev = 0x7fffffff;
1646 /* snd_mtxlock(sc->lock); */
1647 for (size = ch->size / 2; size > 0; size /= 2) {
1648 if (abs(size - blocksize) < abs(prev - blocksize))
1649 prev = size;
1650 else
1651 break;
1652 }
1653
1654 ch->blk = prev / ch->unit;
1655 if (ch->dir == PCMDIR_PLAY)
1656 ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
1657 else
1658 ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
1659 /* set channel buffer information */
1660 /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
1661 if (ch->dir == PCMDIR_PLAY)
1662 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1663 else
1664 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1665 bsize *= ch->unit;
1666 bcnt = ch->size / bsize;
1667 sndbuf_resize(ch->buffer, bcnt, bsize);
1668 /* snd_mtxunlock(sc->lock); */
1669
1670 #if(0)
1671 device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
1672 #endif
1673 return prev;
1674 }
1675
1676 /* semantic note: must start at beginning of buffer */
1677 static int
envy24htchan_trigger(kobj_t obj,void * data,int go)1678 envy24htchan_trigger(kobj_t obj, void *data, int go)
1679 {
1680 struct sc_chinfo *ch = data;
1681 struct sc_info *sc = ch->parent;
1682 u_int32_t ptr;
1683 int slot;
1684 int error = 0;
1685 #if 0
1686 int i;
1687
1688 device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1689 #endif
1690 snd_mtxlock(sc->lock);
1691 if (ch->dir == PCMDIR_PLAY)
1692 slot = 0;
1693 else
1694 slot = 1;
1695 switch (go) {
1696 case PCMTRIG_START:
1697 #if(0)
1698 device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1699 #endif
1700 /* check or set channel speed */
1701 if (sc->run[0] == 0 && sc->run[1] == 0) {
1702 sc->speed = envy24ht_setspeed(sc, ch->speed);
1703 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1704 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1705 }
1706 else if (ch->speed != 0 && ch->speed != sc->speed) {
1707 error = -1;
1708 goto fail;
1709 }
1710 if (ch->speed == 0)
1711 ch->channel->speed = sc->speed;
1712 /* start or enable channel */
1713 sc->run[slot]++;
1714 if (sc->run[slot] == 1) {
1715 /* first channel */
1716 ch->offset = 0;
1717 sc->blk[slot] = ch->blk;
1718 }
1719 else {
1720 ptr = envy24ht_gethwptr(sc, ch->dir);
1721 ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1722 (ch->size / 4)) * 4 / ch->unit;
1723 if (ch->blk < sc->blk[slot])
1724 sc->blk[slot] = ch->blk;
1725 }
1726 if (ch->dir == PCMDIR_PLAY) {
1727 ch->emldma(ch);
1728 envy24ht_setvolume(sc, ch->num);
1729 }
1730 envy24ht_updintr(sc, ch->dir);
1731 if (sc->run[slot] == 1)
1732 envy24ht_start(sc, ch->dir);
1733 ch->run = 1;
1734 break;
1735 case PCMTRIG_EMLDMAWR:
1736 #if(0)
1737 device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1738 #endif
1739 if (ch->run != 1) {
1740 error = -1;
1741 goto fail;
1742 }
1743 ch->emldma(ch);
1744 break;
1745 case PCMTRIG_EMLDMARD:
1746 #if(0)
1747 device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1748 #endif
1749 if (ch->run != 1) {
1750 error = -1;
1751 goto fail;
1752 }
1753 ch->emldma(ch);
1754 break;
1755 case PCMTRIG_ABORT:
1756 if (ch->run) {
1757 #if(0)
1758 device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1759 #endif
1760 ch->run = 0;
1761 sc->run[slot]--;
1762 if (ch->dir == PCMDIR_PLAY)
1763 envy24ht_mutevolume(sc, ch->num);
1764 if (sc->run[slot] == 0) {
1765 envy24ht_stop(sc, ch->dir);
1766 sc->intr[slot] = 0;
1767 }
1768 /* else if (ch->blk == sc->blk[slot]) {
1769 sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1770 for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1771 if (sc->chan[i].dir == ch->dir &&
1772 sc->chan[i].run == 1 &&
1773 sc->chan[i].blk < sc->blk[slot])
1774 sc->blk[slot] = sc->chan[i].blk;
1775 }
1776 if (ch->blk != sc->blk[slot])
1777 envy24ht_updintr(sc, ch->dir);
1778 }*/
1779 }
1780 break;
1781 }
1782 fail:
1783 snd_mtxunlock(sc->lock);
1784 return (error);
1785 }
1786
1787 static u_int32_t
envy24htchan_getptr(kobj_t obj,void * data)1788 envy24htchan_getptr(kobj_t obj, void *data)
1789 {
1790 struct sc_chinfo *ch = data;
1791 struct sc_info *sc = ch->parent;
1792 u_int32_t ptr, rtn;
1793
1794 #if(0)
1795 device_printf(sc->dev, "envy24htchan_getptr()\n");
1796 #endif
1797 snd_mtxlock(sc->lock);
1798 ptr = envy24ht_gethwptr(sc, ch->dir);
1799 rtn = ptr * ch->unit;
1800 snd_mtxunlock(sc->lock);
1801
1802 #if(0)
1803 device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1804 rtn);
1805 #endif
1806 return rtn;
1807 }
1808
1809 static struct pcmchan_caps *
envy24htchan_getcaps(kobj_t obj,void * data)1810 envy24htchan_getcaps(kobj_t obj, void *data)
1811 {
1812 struct sc_chinfo *ch = data;
1813 struct sc_info *sc = ch->parent;
1814 struct pcmchan_caps *rtn;
1815
1816 #if(0)
1817 device_printf(sc->dev, "envy24htchan_getcaps()\n");
1818 #endif
1819 snd_mtxlock(sc->lock);
1820 if (ch->dir == PCMDIR_PLAY) {
1821 if (sc->run[0] == 0)
1822 rtn = &envy24ht_playcaps;
1823 else
1824 rtn = &sc->caps[0];
1825 }
1826 else {
1827 if (sc->run[1] == 0)
1828 rtn = &envy24ht_reccaps;
1829 else
1830 rtn = &sc->caps[1];
1831 }
1832 snd_mtxunlock(sc->lock);
1833
1834 return rtn;
1835 }
1836
1837 static kobj_method_t envy24htchan_methods[] = {
1838 KOBJMETHOD(channel_init, envy24htchan_init),
1839 KOBJMETHOD(channel_free, envy24htchan_free),
1840 KOBJMETHOD(channel_setformat, envy24htchan_setformat),
1841 KOBJMETHOD(channel_setspeed, envy24htchan_setspeed),
1842 KOBJMETHOD(channel_setblocksize, envy24htchan_setblocksize),
1843 KOBJMETHOD(channel_trigger, envy24htchan_trigger),
1844 KOBJMETHOD(channel_getptr, envy24htchan_getptr),
1845 KOBJMETHOD(channel_getcaps, envy24htchan_getcaps),
1846 KOBJMETHOD_END
1847 };
1848 CHANNEL_DECLARE(envy24htchan);
1849
1850 /* -------------------------------------------------------------------- */
1851
1852 /* mixer interface */
1853
1854 static int
envy24htmixer_init(struct snd_mixer * m)1855 envy24htmixer_init(struct snd_mixer *m)
1856 {
1857 struct sc_info *sc = mix_getdevinfo(m);
1858
1859 #if(0)
1860 device_printf(sc->dev, "envy24htmixer_init()\n");
1861 #endif
1862 if (sc == NULL)
1863 return -1;
1864
1865 /* set volume control rate */
1866 snd_mtxlock(sc->lock);
1867 #if 0
1868 envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1869 #endif
1870
1871 pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1872
1873 mix_setdevs(m, ENVY24HT_MIX_MASK);
1874 mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1875
1876 snd_mtxunlock(sc->lock);
1877
1878 return 0;
1879 }
1880
1881 static int
envy24htmixer_reinit(struct snd_mixer * m)1882 envy24htmixer_reinit(struct snd_mixer *m)
1883 {
1884 struct sc_info *sc = mix_getdevinfo(m);
1885
1886 if (sc == NULL)
1887 return -1;
1888 #if(0)
1889 device_printf(sc->dev, "envy24htmixer_reinit()\n");
1890 #endif
1891
1892 return 0;
1893 }
1894
1895 static int
envy24htmixer_uninit(struct snd_mixer * m)1896 envy24htmixer_uninit(struct snd_mixer *m)
1897 {
1898 struct sc_info *sc = mix_getdevinfo(m);
1899
1900 if (sc == NULL)
1901 return -1;
1902 #if(0)
1903 device_printf(sc->dev, "envy24htmixer_uninit()\n");
1904 #endif
1905
1906 return 0;
1907 }
1908
1909 static int
envy24htmixer_set(struct snd_mixer * m,unsigned dev,unsigned left,unsigned right)1910 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1911 {
1912 struct sc_info *sc = mix_getdevinfo(m);
1913 int ch = envy24ht_mixmap[dev];
1914 int hwch;
1915 int i;
1916
1917 if (sc == NULL)
1918 return -1;
1919 if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1920 return -1;
1921 if (dev != 0 && ch == -1)
1922 return -1;
1923 hwch = envy24ht_chanmap[ch];
1924 #if(0)
1925 device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1926 dev, left, right);
1927 #endif
1928
1929 snd_mtxlock(sc->lock);
1930 if (dev == 0) {
1931 for (i = 0; i < sc->dacn; i++) {
1932 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1933 }
1934 }
1935 else {
1936 /* set volume value for hardware */
1937 if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1938 sc->left[hwch] = ENVY24HT_VOL_MUTE;
1939 if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1940 sc->right[hwch] = ENVY24HT_VOL_MUTE;
1941
1942 /* set volume for record channel and running play channel */
1943 if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1944 envy24ht_setvolume(sc, hwch);
1945 }
1946 snd_mtxunlock(sc->lock);
1947
1948 return right << 8 | left;
1949 }
1950
1951 static u_int32_t
envy24htmixer_setrecsrc(struct snd_mixer * m,u_int32_t src)1952 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1953 {
1954 struct sc_info *sc = mix_getdevinfo(m);
1955 int ch = envy24ht_mixmap[src];
1956 #if(0)
1957 device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1958 #endif
1959
1960 if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1961 sc->src = ch;
1962 return src;
1963 }
1964
1965 static kobj_method_t envy24htmixer_methods[] = {
1966 KOBJMETHOD(mixer_init, envy24htmixer_init),
1967 KOBJMETHOD(mixer_reinit, envy24htmixer_reinit),
1968 KOBJMETHOD(mixer_uninit, envy24htmixer_uninit),
1969 KOBJMETHOD(mixer_set, envy24htmixer_set),
1970 KOBJMETHOD(mixer_setrecsrc, envy24htmixer_setrecsrc),
1971 KOBJMETHOD_END
1972 };
1973 MIXER_DECLARE(envy24htmixer);
1974
1975 /* -------------------------------------------------------------------- */
1976
1977 /* The interrupt handler */
1978 static void
envy24ht_intr(void * p)1979 envy24ht_intr(void *p)
1980 {
1981 struct sc_info *sc = (struct sc_info *)p;
1982 struct sc_chinfo *ch;
1983 u_int32_t ptr, dsize, feed;
1984 int i;
1985
1986 #if(0)
1987 device_printf(sc->dev, "envy24ht_intr()\n");
1988 #endif
1989 snd_mtxlock(sc->lock);
1990 if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1991 #if(0)
1992 device_printf(sc->dev, "envy24ht_intr(): play\n");
1993 #endif
1994 dsize = sc->psize / 4;
1995 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
1996 #if(0)
1997 device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
1998 #endif
1999 ptr -= ptr % sc->blk[0];
2000 feed = (ptr + dsize - sc->intr[0]) % dsize;
2001 #if(0)
2002 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2003 #endif
2004 for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
2005 ch = &sc->chan[i];
2006 #if(0)
2007 if (ch->run)
2008 device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
2009 #endif
2010 if (ch->run && ch->blk <= feed) {
2011 snd_mtxunlock(sc->lock);
2012 chn_intr(ch->channel);
2013 snd_mtxlock(sc->lock);
2014 }
2015 }
2016 sc->intr[0] = ptr;
2017 envy24ht_updintr(sc, PCMDIR_PLAY);
2018 }
2019 if (envy24ht_checkintr(sc, PCMDIR_REC)) {
2020 #if(0)
2021 device_printf(sc->dev, "envy24ht_intr(): rec\n");
2022 #endif
2023 dsize = sc->rsize / 4;
2024 ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
2025 ptr -= ptr % sc->blk[1];
2026 feed = (ptr + dsize - sc->intr[1]) % dsize;
2027 for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
2028 ch = &sc->chan[i];
2029 if (ch->run && ch->blk <= feed) {
2030 snd_mtxunlock(sc->lock);
2031 chn_intr(ch->channel);
2032 snd_mtxlock(sc->lock);
2033 }
2034 }
2035 sc->intr[1] = ptr;
2036 envy24ht_updintr(sc, PCMDIR_REC);
2037 }
2038 snd_mtxunlock(sc->lock);
2039
2040 return;
2041 }
2042
2043 /*
2044 * Probe and attach the card
2045 */
2046
2047 static int
envy24ht_pci_probe(device_t dev)2048 envy24ht_pci_probe(device_t dev)
2049 {
2050 u_int16_t sv, sd;
2051 int i;
2052
2053 #if(0)
2054 printf("envy24ht_pci_probe()\n");
2055 #endif
2056 if (pci_get_device(dev) == PCID_ENVY24HT &&
2057 pci_get_vendor(dev) == PCIV_ENVY24) {
2058 sv = pci_get_subvendor(dev);
2059 sd = pci_get_subdevice(dev);
2060 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2061 if (cfg_table[i].subvendor == sv &&
2062 cfg_table[i].subdevice == sd) {
2063 break;
2064 }
2065 }
2066 device_set_desc(dev, cfg_table[i].name);
2067 #if(0)
2068 printf("envy24ht_pci_probe(): return 0\n");
2069 #endif
2070 return 0;
2071 }
2072 else {
2073 #if(0)
2074 printf("envy24ht_pci_probe(): return ENXIO\n");
2075 #endif
2076 return ENXIO;
2077 }
2078 }
2079
2080 static void
envy24ht_dmapsetmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)2081 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2082 {
2083 struct sc_info *sc = arg;
2084
2085 #if(0)
2086 device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2087 if (bootverbose) {
2088 printf("envy24ht(play): setmap %lx, %lx; ",
2089 (unsigned long)segs->ds_addr,
2090 (unsigned long)segs->ds_len);
2091 }
2092 #endif
2093 envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, (uint32_t)segs->ds_addr, 4);
2094 envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2095 }
2096
2097 static void
envy24ht_dmarsetmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)2098 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2099 {
2100 struct sc_info *sc = arg;
2101
2102 #if(0)
2103 device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2104 if (bootverbose) {
2105 printf("envy24ht(record): setmap %lx, %lx; ",
2106 (unsigned long)segs->ds_addr,
2107 (unsigned long)segs->ds_len);
2108 }
2109 #endif
2110 envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, (uint32_t)segs->ds_addr, 4);
2111 envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2112 }
2113
2114 static void
envy24ht_dmafree(struct sc_info * sc)2115 envy24ht_dmafree(struct sc_info *sc)
2116 {
2117 #if(0)
2118 device_printf(sc->dev, "envy24ht_dmafree():");
2119 if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2120 else printf(" sc->rmap(null)");
2121 if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2122 else printf(" sc->pmap(null)");
2123 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2124 else printf(" sc->rbuf(null)");
2125 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2126 else printf(" sc->pbuf(null)\n");
2127 #endif
2128 #if(0)
2129 if (sc->rmap)
2130 bus_dmamap_unload(sc->dmat, sc->rmap);
2131 if (sc->pmap)
2132 bus_dmamap_unload(sc->dmat, sc->pmap);
2133 if (sc->rbuf)
2134 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2135 if (sc->pbuf)
2136 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2137 #else
2138 bus_dmamap_unload(sc->dmat, sc->rmap);
2139 bus_dmamap_unload(sc->dmat, sc->pmap);
2140 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2141 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2142 #endif
2143
2144 sc->rmap = sc->pmap = NULL;
2145 sc->pbuf = NULL;
2146 sc->rbuf = NULL;
2147
2148 return;
2149 }
2150
2151 static int
envy24ht_dmainit(struct sc_info * sc)2152 envy24ht_dmainit(struct sc_info *sc)
2153 {
2154
2155 #if(0)
2156 device_printf(sc->dev, "envy24ht_dmainit()\n");
2157 #endif
2158 /* init values */
2159 sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2160 sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2161 sc->pbuf = NULL;
2162 sc->rbuf = NULL;
2163 sc->pmap = sc->rmap = NULL;
2164 sc->blk[0] = sc->blk[1] = 0;
2165
2166 /* allocate DMA buffer */
2167 #if(0)
2168 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2169 #endif
2170 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2171 goto bad;
2172 #if(0)
2173 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2174 #endif
2175 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2176 goto bad;
2177 #if(0)
2178 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2179 #endif
2180 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, BUS_DMA_NOWAIT))
2181 goto bad;
2182 #if(0)
2183 device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2184 #endif
2185 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, BUS_DMA_NOWAIT))
2186 goto bad;
2187 bzero(sc->pbuf, sc->psize);
2188 bzero(sc->rbuf, sc->rsize);
2189
2190 return 0;
2191 bad:
2192 envy24ht_dmafree(sc);
2193 return ENOSPC;
2194 }
2195
2196 static void
envy24ht_putcfg(struct sc_info * sc)2197 envy24ht_putcfg(struct sc_info *sc)
2198 {
2199 device_printf(sc->dev, "system configuration\n");
2200 printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2201 sc->cfg->subvendor, sc->cfg->subdevice);
2202 printf(" XIN2 Clock Source: ");
2203 switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2204 case 0x00:
2205 printf("24.576MHz(96kHz*256)\n");
2206 break;
2207 case 0x40:
2208 printf("49.152MHz(192kHz*256)\n");
2209 break;
2210 case 0x80:
2211 printf("reserved\n");
2212 break;
2213 default:
2214 printf("illeagal system setting\n");
2215 }
2216 printf(" MPU-401 UART(s) #: ");
2217 if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2218 printf("1\n");
2219 else
2220 printf("not implemented\n");
2221 switch (sc->adcn) {
2222 case 0x01:
2223 case 0x02:
2224 printf(" ADC #: ");
2225 printf("%d\n", sc->adcn);
2226 break;
2227 case 0x03:
2228 printf(" ADC #: ");
2229 printf("%d", 1);
2230 printf(" and SPDIF receiver connected\n");
2231 break;
2232 default:
2233 printf(" no physical inputs\n");
2234 }
2235 printf(" DAC #: ");
2236 printf("%d\n", sc->dacn);
2237 printf(" Multi-track converter type: ");
2238 if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2239 printf("AC'97(SDATA_OUT:");
2240 if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2241 printf("packed");
2242 else
2243 printf("split");
2244 printf(")\n");
2245 }
2246 else {
2247 printf("I2S(");
2248 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2249 printf("with volume, ");
2250 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2251 printf("192KHz support, ");
2252 else
2253 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2254 printf("192KHz support, ");
2255 else
2256 printf("48KHz support, ");
2257 switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2258 case ENVY24HT_CCSM_I2S_16BIT:
2259 printf("16bit resolution, ");
2260 break;
2261 case ENVY24HT_CCSM_I2S_18BIT:
2262 printf("18bit resolution, ");
2263 break;
2264 case ENVY24HT_CCSM_I2S_20BIT:
2265 printf("20bit resolution, ");
2266 break;
2267 case ENVY24HT_CCSM_I2S_24BIT:
2268 printf("24bit resolution, ");
2269 break;
2270 }
2271 printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2272 }
2273 printf(" S/PDIF(IN/OUT): ");
2274 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2275 printf("1/");
2276 else
2277 printf("0/");
2278 if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2279 printf("1 ");
2280 else
2281 printf("0 ");
2282 if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2283 printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2284 printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2285 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2286 }
2287
2288 static int
envy24ht_init(struct sc_info * sc)2289 envy24ht_init(struct sc_info *sc)
2290 {
2291 u_int32_t data;
2292 #if(0)
2293 int rtn;
2294 #endif
2295 int i;
2296 u_int32_t sv, sd;
2297
2298
2299 #if(0)
2300 device_printf(sc->dev, "envy24ht_init()\n");
2301 #endif
2302
2303 /* reset chip */
2304 #if 0
2305 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2306 DELAY(200);
2307 envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2308 DELAY(200);
2309
2310 /* legacy hardware disable */
2311 data = pci_read_config(sc->dev, PCIR_LAC, 2);
2312 data |= PCIM_LAC_DISABLE;
2313 pci_write_config(sc->dev, PCIR_LAC, data, 2);
2314 #endif
2315
2316 /* check system configuration */
2317 sc->cfg = NULL;
2318 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2319 /* 1st: search configuration from table */
2320 sv = pci_get_subvendor(sc->dev);
2321 sd = pci_get_subdevice(sc->dev);
2322 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2323 #if(0)
2324 device_printf(sc->dev, "Set configuration from table\n");
2325 #endif
2326 sc->cfg = &cfg_table[i];
2327 break;
2328 }
2329 }
2330 if (sc->cfg == NULL) {
2331 /* 2nd: read configuration from table */
2332 sc->cfg = envy24ht_rom2cfg(sc);
2333 }
2334 sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2335 sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2336
2337 if (1 /* bootverbose */) {
2338 envy24ht_putcfg(sc);
2339 }
2340
2341 /* set system configuration */
2342 envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2343 envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2344 envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2345 envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2346 envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2347 envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2348 envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2349
2350 if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2351 envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2352 envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2353 envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2354 }
2355
2356 for (i = 0; i < sc->adcn; i++) {
2357 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2358 sc->cfg->codec->init(sc->adc[i]);
2359 }
2360 for (i = 0; i < sc->dacn; i++) {
2361 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2362 sc->cfg->codec->init(sc->dac[i]);
2363 }
2364
2365 /* initialize DMA buffer */
2366 #if(0)
2367 device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2368 #endif
2369 if (envy24ht_dmainit(sc))
2370 return ENOSPC;
2371
2372 /* initialize status */
2373 sc->run[0] = sc->run[1] = 0;
2374 sc->intr[0] = sc->intr[1] = 0;
2375 sc->speed = 0;
2376 sc->caps[0].fmtlist = envy24ht_playfmt;
2377 sc->caps[1].fmtlist = envy24ht_recfmt;
2378
2379 /* set channel router */
2380 #if 0
2381 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2382 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2383 envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2384 #endif
2385
2386 /* set macro interrupt mask */
2387 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2388 envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2389 data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2390 #if(0)
2391 device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2392 #endif
2393
2394 return 0;
2395 }
2396
2397 static int
envy24ht_alloc_resource(struct sc_info * sc)2398 envy24ht_alloc_resource(struct sc_info *sc)
2399 {
2400 /* allocate I/O port resource */
2401 sc->csid = PCIR_CCS;
2402 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2403 &sc->csid, 0, ~0, 1, RF_ACTIVE);
2404 sc->mtid = ENVY24HT_PCIR_MT;
2405 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2406 &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2407 if (!sc->cs || !sc->mt) {
2408 device_printf(sc->dev, "unable to map IO port space\n");
2409 return ENXIO;
2410 }
2411 sc->cst = rman_get_bustag(sc->cs);
2412 sc->csh = rman_get_bushandle(sc->cs);
2413 sc->mtt = rman_get_bustag(sc->mt);
2414 sc->mth = rman_get_bushandle(sc->mt);
2415 #if(0)
2416 device_printf(sc->dev,
2417 "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2418 pci_read_config(sc->dev, PCIR_CCS, 4),
2419 pci_read_config(sc->dev, PCIR_MT, 4));
2420 #endif
2421
2422 /* allocate interrupt resource */
2423 sc->irqid = 0;
2424 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2425 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2426 if (!sc->irq ||
2427 snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24ht_intr, sc, &sc->ih)) {
2428 device_printf(sc->dev, "unable to map interrupt\n");
2429 return ENXIO;
2430 }
2431
2432 /* allocate DMA resource */
2433 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2434 /*alignment*/4,
2435 /*boundary*/0,
2436 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
2437 /*highaddr*/BUS_SPACE_MAXADDR,
2438 /*filter*/NULL, /*filterarg*/NULL,
2439 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2440 /*nsegments*/1, /*maxsegsz*/0x3ffff,
2441 /*flags*/0, /*lockfunc*/NULL,
2442 /*lockarg*/NULL, &sc->dmat) != 0) {
2443 device_printf(sc->dev, "unable to create dma tag\n");
2444 return ENXIO;
2445 }
2446
2447 return 0;
2448 }
2449
2450 static int
envy24ht_pci_attach(device_t dev)2451 envy24ht_pci_attach(device_t dev)
2452 {
2453 struct sc_info *sc;
2454 char status[SND_STATUSLEN];
2455 int err = 0;
2456 int i;
2457
2458 #if(0)
2459 device_printf(dev, "envy24ht_pci_attach()\n");
2460 #endif
2461 /* get sc_info data area */
2462 if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) {
2463 device_printf(dev, "cannot allocate softc\n");
2464 return ENXIO;
2465 }
2466
2467 bzero(sc, sizeof(*sc));
2468 sc->lock = snd_mtxcreate(device_get_nameunit(dev),
2469 "snd_envy24ht softc");
2470 sc->dev = dev;
2471
2472 /* initialize PCI interface */
2473 pci_enable_busmaster(dev);
2474
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;
2480 }
2481
2482 /* initialize card */
2483 err = envy24ht_init(sc);
2484 if (err) {
2485 device_printf(dev, "unable to initialize the card\n");
2486 goto bad;
2487 }
2488
2489 /* set multi track mixer */
2490 mixer_init(dev, &envy24htmixer_class, sc);
2491
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++;
2505 }
2506
2507 /* set status iformation */
2508 snprintf(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);
2516
2517 return 0;
2518
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]);
2532 }
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 free(sc, M_ENVY24HT);
2541 return err;
2542 }
2543
2544 static int
envy24ht_pci_detach(device_t dev)2545 envy24ht_pci_detach(device_t dev)
2546 {
2547 struct sc_info *sc;
2548 int r;
2549 int i;
2550
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;
2560
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]);
2567 }
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 free(sc, M_ENVY24HT);
2576 return 0;
2577 }
2578
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 }
2585 };
2586
2587 static driver_t envy24ht_driver = {
2588 "pcm",
2589 envy24ht_methods,
2590 #if __FreeBSD_version > 500000
2591 PCM_SOFTC_SIZE,
2592 #else
2593 sizeof(struct snddev_info),
2594 #endif
2595 };
2596
2597 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0);
2598 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2599 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2600 MODULE_VERSION(snd_envy24ht, 1);
2601