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