xref: /dragonfly/sys/dev/sound/pci/envy24ht.c (revision 030b0c8c4cf27c560ccec70410c8e21934ae677d)
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 <bus/pci/pcireg.h>
50 #include <bus/pci/pcivar.h>
51 
52 #include "mixer_if.h"
53 
54 SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/envy24ht.c 274035 2014-11-03 11:11:45Z bapt $");
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 lock         *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 = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
630         if (buff == NULL) {
631 #if(0)
632                 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
633 #endif
634                 return NULL;
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 = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
670           if (buff == NULL) {
671 #if(0)
672                     device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
673 #endif
674                     return NULL;
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                     kfree(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 = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
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                     kfree(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           kfree(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 regptr, regintr;
1158           u_int32_t mask, intr;
1159           u_int32_t ptr, size, 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                     size = sc->psize / 4;
1168                     regptr = ENVY24HT_MT_PCNT;
1169                     regintr = ENVY24HT_MT_PTERM;
1170                     mask = ~ENVY24HT_MT_INT_PMASK;
1171           }
1172           else {
1173                     blk = sc->blk[1];
1174                     size = sc->rsize / 4;
1175                     regptr = ENVY24HT_MT_RCNT;
1176                     regintr = ENVY24HT_MT_RTERM;
1177                     mask = ~ENVY24HT_MT_INT_RMASK;
1178           }
1179 
1180           ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1;
1181           /*
1182           cnt = blk - ptr % blk - 1;
1183           if (cnt == 0)
1184                     cnt = blk - 1;
1185           */
1186           cnt = blk - 1;
1187 #if(0)
1188           device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1189 #endif
1190           envy24ht_wrmt(sc, regintr, cnt, 2);
1191           intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1192 #if(0)
1193           device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1194 #endif
1195           envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
1196 #if(0)
1197           device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
1198                           envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
1199 #endif
1200 
1201           return;
1202 }
1203 
1204 #if 0
1205 static void
envy24ht_maskintr(struct sc_info * sc,int dir)1206 envy24ht_maskintr(struct sc_info *sc, int dir)
1207 {
1208           u_int32_t mask, intr;
1209 
1210 #if(0)
1211           device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
1212 #endif
1213           if (dir == PCMDIR_PLAY)
1214                     mask = ENVY24HT_MT_INT_PMASK;
1215           else
1216                     mask = ENVY24HT_MT_INT_RMASK;
1217           intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
1218           envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
1219 
1220           return;
1221 }
1222 #endif
1223 
1224 static int
envy24ht_checkintr(struct sc_info * sc,int dir)1225 envy24ht_checkintr(struct sc_info *sc, int dir)
1226 {
1227           u_int32_t mask, stat, intr, rtn;
1228 
1229 #if(0)
1230           device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
1231 #endif
1232           intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
1233           if (dir == PCMDIR_PLAY) {
1234                     if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
1235                               mask = ~ENVY24HT_MT_INT_RSTAT;
1236                               envy24ht_wrmt(sc, 0x1a, 0x01, 1);
1237                               envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);
1238                               stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1239                               envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
1240                     }
1241           }
1242           else {
1243                     if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
1244                               mask = ~ENVY24HT_MT_INT_PSTAT;
1245 #if 0
1246                               stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
1247 #endif
1248                               envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
1249                               stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1250                               envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
1251                     }
1252           }
1253 
1254           return rtn;
1255 }
1256 
1257 static void
envy24ht_start(struct sc_info * sc,int dir)1258 envy24ht_start(struct sc_info *sc, int dir)
1259 {
1260           u_int32_t stat, sw;
1261 
1262 #if(0)
1263           device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
1264 #endif
1265           if (dir == PCMDIR_PLAY)
1266                     sw = ENVY24HT_MT_PCTL_PSTART;
1267           else
1268                     sw = ENVY24HT_MT_PCTL_RSTART;
1269 
1270           stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1271           envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
1272 #if(0)
1273           DELAY(100);
1274           device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
1275           device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
1276 #endif
1277 
1278           return;
1279 }
1280 
1281 static void
envy24ht_stop(struct sc_info * sc,int dir)1282 envy24ht_stop(struct sc_info *sc, int dir)
1283 {
1284           u_int32_t stat, sw;
1285 
1286 #if(0)
1287           device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir);
1288 #endif
1289           if (dir == PCMDIR_PLAY)
1290                     sw = ~ENVY24HT_MT_PCTL_PSTART;
1291           else
1292                     sw = ~ENVY24HT_MT_PCTL_RSTART;
1293 
1294           stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1295           envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1);
1296 
1297           return;
1298 }
1299 
1300 #if 0
1301 static int
envy24ht_route(struct sc_info * sc,int dac,int class,int adc,int rev)1302 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1303 {
1304           return 0;
1305 }
1306 #endif
1307 
1308 /* -------------------------------------------------------------------- */
1309 
1310 /* buffer copy routines */
1311 static void
envy24ht_p32sl(struct sc_chinfo * ch)1312 envy24ht_p32sl(struct sc_chinfo *ch)
1313 {
1314           int length;
1315           sample32_t *dmabuf;
1316           u_int32_t *data;
1317           int src, dst, ssize, dsize, slot;
1318           int i;
1319 
1320           length = sndbuf_getready(ch->buffer) / 8;
1321           dmabuf = ch->parent->pbuf;
1322           data = (u_int32_t *)ch->data;
1323           src = sndbuf_getreadyptr(ch->buffer) / 4;
1324           dst = src / 2 + ch->offset;
1325           ssize = ch->size / 4;
1326           dsize = ch->size / 8;
1327           slot = ch->num * 2;
1328 
1329           for (i = 0; i < length; i++) {
1330                     dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
1331                     dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1332                     dst++;
1333                     dst %= dsize;
1334                     src += 2;
1335                     src %= ssize;
1336           }
1337 
1338           return;
1339 }
1340 
1341 static void
envy24ht_p16sl(struct sc_chinfo * ch)1342 envy24ht_p16sl(struct sc_chinfo *ch)
1343 {
1344           int length;
1345           sample32_t *dmabuf;
1346           u_int16_t *data;
1347           int src, dst, ssize, dsize, slot;
1348           int i;
1349 
1350 #if(0)
1351           device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
1352 #endif
1353           length = sndbuf_getready(ch->buffer) / 4;
1354           dmabuf = ch->parent->pbuf;
1355           data = (u_int16_t *)ch->data;
1356           src = sndbuf_getreadyptr(ch->buffer) / 2;
1357           dst = src / 2 + ch->offset;
1358           ssize = ch->size / 2;
1359           dsize = ch->size / 4;
1360           slot = ch->num * 2;
1361 #if(0)
1362           device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1363 #endif
1364 
1365           for (i = 0; i < length; i++) {
1366                     dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1367                     dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1368 #if(0)
1369                     if (i < 16) {
1370                               printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
1371                               printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
1372                     }
1373 #endif
1374                     dst++;
1375                     dst %= dsize;
1376                     src += 2;
1377                     src %= ssize;
1378           }
1379 #if(0)
1380           printf("\n");
1381 #endif
1382 
1383           return;
1384 }
1385 
1386 static void
envy24ht_p8u(struct sc_chinfo * ch)1387 envy24ht_p8u(struct sc_chinfo *ch)
1388 {
1389           int length;
1390           sample32_t *dmabuf;
1391           u_int8_t *data;
1392           int src, dst, ssize, dsize, slot;
1393           int i;
1394 
1395           length = sndbuf_getready(ch->buffer) / 2;
1396           dmabuf = ch->parent->pbuf;
1397           data = (u_int8_t *)ch->data;
1398           src = sndbuf_getreadyptr(ch->buffer);
1399           dst = src / 2 + ch->offset;
1400           ssize = ch->size;
1401           dsize = ch->size / 4;
1402           slot = ch->num * 2;
1403 
1404           for (i = 0; i < length; i++) {
1405                     dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1406                     dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1407                     dst++;
1408                     dst %= dsize;
1409                     src += 2;
1410                     src %= ssize;
1411           }
1412 
1413           return;
1414 }
1415 
1416 static void
envy24ht_r32sl(struct sc_chinfo * ch)1417 envy24ht_r32sl(struct sc_chinfo *ch)
1418 {
1419           int length;
1420           sample32_t *dmabuf;
1421           u_int32_t *data;
1422           int src, dst, ssize, dsize, slot;
1423           int i;
1424 
1425           length = sndbuf_getfree(ch->buffer) / 8;
1426           dmabuf = ch->parent->rbuf;
1427           data = (u_int32_t *)ch->data;
1428           dst = sndbuf_getfreeptr(ch->buffer) / 4;
1429           src = dst / 2 + ch->offset;
1430           dsize = ch->size / 4;
1431           ssize = ch->size / 8;
1432           slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1433 
1434           for (i = 0; i < length; i++) {
1435                     data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1436                     data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1437                     dst += 2;
1438                     dst %= dsize;
1439                     src++;
1440                     src %= ssize;
1441           }
1442 
1443           return;
1444 }
1445 
1446 static void
envy24ht_r16sl(struct sc_chinfo * ch)1447 envy24ht_r16sl(struct sc_chinfo *ch)
1448 {
1449           int length;
1450           sample32_t *dmabuf;
1451           u_int16_t *data;
1452           int src, dst, ssize, dsize, slot;
1453           int i;
1454 
1455           length = sndbuf_getfree(ch->buffer) / 4;
1456           dmabuf = ch->parent->rbuf;
1457           data = (u_int16_t *)ch->data;
1458           dst = sndbuf_getfreeptr(ch->buffer) / 2;
1459           src = dst / 2 + ch->offset;
1460           dsize = ch->size / 2;
1461           ssize = ch->size / 8;
1462           slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1463 
1464           for (i = 0; i < length; i++) {
1465                     data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1466                     data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1467                     dst += 2;
1468                     dst %= dsize;
1469                     src++;
1470                     src %= ssize;
1471           }
1472 
1473           return;
1474 }
1475 
1476 /* -------------------------------------------------------------------- */
1477 
1478 /* channel interface */
1479 static void *
envy24htchan_init(kobj_t obj,void * devinfo,struct snd_dbuf * b,struct pcm_channel * c,int dir)1480 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1481 {
1482           struct sc_info      *sc = (struct sc_info *)devinfo;
1483           struct sc_chinfo *ch;
1484           unsigned num;
1485 
1486 #if(0)
1487           device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
1488 #endif
1489           snd_mtxlock(sc->lock);
1490 #if 0
1491           if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1492               (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1493                     snd_mtxunlock(sc->lock);
1494                     return NULL;
1495           }
1496 #endif
1497           num = sc->chnum;
1498 
1499           ch = &sc->chan[num];
1500           ch->size = 8 * ENVY24HT_SAMPLE_NUM;
1501           ch->data = kmalloc(ch->size, M_ENVY24HT, M_WAITOK | M_ZERO);
1502           if (ch->data == NULL) {
1503                     ch->size = 0;
1504                     ch = NULL;
1505           }
1506           else {
1507                     ch->buffer = b;
1508                     ch->channel = c;
1509                     ch->parent = sc;
1510                     ch->dir = dir;
1511                     /* set channel map */
1512                     ch->num = envy24ht_chanmap[num];
1513                     snd_mtxunlock(sc->lock);
1514                     sndbuf_setup(ch->buffer, ch->data, ch->size);
1515                     snd_mtxlock(sc->lock);
1516                     /* these 2 values are dummy */
1517                     ch->unit = 4;
1518                     ch->blk = 10240;
1519           }
1520           snd_mtxunlock(sc->lock);
1521 
1522           return ch;
1523 }
1524 
1525 static int
envy24htchan_free(kobj_t obj,void * data)1526 envy24htchan_free(kobj_t obj, void *data)
1527 {
1528           struct sc_chinfo *ch = data;
1529           struct sc_info *sc = ch->parent;
1530 
1531 #if(0)
1532           device_printf(sc->dev, "envy24htchan_free()\n");
1533 #endif
1534           snd_mtxlock(sc->lock);
1535           if (ch->data != NULL) {
1536                     kfree(ch->data, M_ENVY24HT);
1537                     ch->data = NULL;
1538           }
1539           snd_mtxunlock(sc->lock);
1540 
1541           return 0;
1542 }
1543 
1544 static int
envy24htchan_setformat(kobj_t obj,void * data,u_int32_t format)1545 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
1546 {
1547           struct sc_chinfo *ch = data;
1548           struct sc_info *sc = ch->parent;
1549           struct envy24ht_emldma *emltab;
1550           /* unsigned int bcnt, bsize; */
1551           int i;
1552 
1553 #if(0)
1554           device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
1555 #endif
1556           snd_mtxlock(sc->lock);
1557           /* check and get format related information */
1558           if (ch->dir == PCMDIR_PLAY)
1559                     emltab = envy24ht_pemltab;
1560           else
1561                     emltab = envy24ht_remltab;
1562           if (emltab == NULL) {
1563                     snd_mtxunlock(sc->lock);
1564                     return -1;
1565           }
1566           for (i = 0; emltab[i].format != 0; i++)
1567                     if (emltab[i].format == format)
1568                               break;
1569           if (emltab[i].format == 0) {
1570                     snd_mtxunlock(sc->lock);
1571                     return -1;
1572           }
1573 
1574           /* set format information */
1575           ch->format = format;
1576           ch->emldma = emltab[i].emldma;
1577           if (ch->unit > emltab[i].unit)
1578                     ch->blk *= ch->unit / emltab[i].unit;
1579           else
1580                     ch->blk /= emltab[i].unit / ch->unit;
1581           ch->unit = emltab[i].unit;
1582 
1583           /* set channel buffer information */
1584           ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
1585 #if 0
1586           if (ch->dir == PCMDIR_PLAY)
1587                     bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1588           else
1589                     bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1590           bsize *= ch->unit;
1591           bcnt = ch->size / bsize;
1592           sndbuf_resize(ch->buffer, bcnt, bsize);
1593 #endif
1594           snd_mtxunlock(sc->lock);
1595 
1596 #if(0)
1597           device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
1598 #endif
1599           return 0;
1600 }
1601 
1602 /*
1603   IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1604   of speed information value. And real hardware speed setting is done
1605   at start triggered(see envy24htchan_trigger()). So, at this function
1606   is called, any value that ENVY24 can use is able to set. But, at
1607   start triggerd, some other channel is running, and that channel's
1608   speed isn't same with, then trigger function will fail.
1609 */
1610 static u_int32_t
envy24htchan_setspeed(kobj_t obj,void * data,u_int32_t speed)1611 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1612 {
1613           struct sc_chinfo *ch = data;
1614           u_int32_t val, prev;
1615           int i;
1616 
1617 #if(0)
1618           device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
1619 #endif
1620           prev = 0x7fffffff;
1621           for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
1622                     if (abs(val - speed) < abs(prev - speed))
1623                               prev = val;
1624                     else
1625                               break;
1626           }
1627           ch->speed = prev;
1628 
1629 #if(0)
1630           device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
1631 #endif
1632           return ch->speed;
1633 }
1634 
1635 static u_int32_t
envy24htchan_setblocksize(kobj_t obj,void * data,u_int32_t blocksize)1636 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1637 {
1638           struct sc_chinfo *ch = data;
1639           /* struct sc_info *sc = ch->parent; */
1640           u_int32_t size, prev;
1641           unsigned int bcnt, bsize;
1642 
1643 #if(0)
1644           device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
1645 #endif
1646           prev = 0x7fffffff;
1647           /* snd_mtxlock(sc->lock); */
1648           for (size = ch->size / 2; size > 0; size /= 2) {
1649                     if (abs(size - blocksize) < abs(prev - blocksize))
1650                               prev = size;
1651                     else
1652                               break;
1653           }
1654 
1655           ch->blk = prev / ch->unit;
1656           if (ch->dir == PCMDIR_PLAY)
1657                     ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
1658           else
1659                     ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
1660         /* set channel buffer information */
1661         /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
1662         if (ch->dir == PCMDIR_PLAY)
1663                 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1664         else
1665                 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1666         bsize *= ch->unit;
1667         bcnt = ch->size / bsize;
1668         sndbuf_resize(ch->buffer, bcnt, bsize);
1669           /* snd_mtxunlock(sc->lock); */
1670 
1671 #if(0)
1672           device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
1673 #endif
1674           return prev;
1675 }
1676 
1677 /* semantic note: must start at beginning of buffer */
1678 static int
envy24htchan_trigger(kobj_t obj,void * data,int go)1679 envy24htchan_trigger(kobj_t obj, void *data, int go)
1680 {
1681           struct sc_chinfo *ch = data;
1682           struct sc_info *sc = ch->parent;
1683           u_int32_t ptr;
1684           int slot;
1685           int error = 0;
1686 #if 0
1687           int i;
1688 
1689           device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1690 #endif
1691           snd_mtxlock(sc->lock);
1692           if (ch->dir == PCMDIR_PLAY)
1693                     slot = 0;
1694           else
1695                     slot = 1;
1696           switch (go) {
1697           case PCMTRIG_START:
1698 #if(0)
1699                     device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1700 #endif
1701                     /* check or set channel speed */
1702                     if (sc->run[0] == 0 && sc->run[1] == 0) {
1703                               sc->speed = envy24ht_setspeed(sc, ch->speed);
1704                               sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1705                               sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1706                     }
1707                     else if (ch->speed != 0 && ch->speed != sc->speed) {
1708                               error = -1;
1709                               goto fail;
1710                     }
1711                     if (ch->speed == 0)
1712                               ch->channel->speed = sc->speed;
1713                     /* start or enable channel */
1714                     sc->run[slot]++;
1715                     if (sc->run[slot] == 1) {
1716                               /* first channel */
1717                               ch->offset = 0;
1718                               sc->blk[slot] = ch->blk;
1719                     }
1720                     else {
1721                               ptr = envy24ht_gethwptr(sc, ch->dir);
1722                               ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1723                                   (ch->size / 4)) * 4 / ch->unit;
1724                               if (ch->blk < sc->blk[slot])
1725                                         sc->blk[slot] = ch->blk;
1726                     }
1727                     if (ch->dir == PCMDIR_PLAY) {
1728                               ch->emldma(ch);
1729                               envy24ht_setvolume(sc, ch->num);
1730                     }
1731                     envy24ht_updintr(sc, ch->dir);
1732                     if (sc->run[slot] == 1)
1733                               envy24ht_start(sc, ch->dir);
1734                     ch->run = 1;
1735                     break;
1736           case PCMTRIG_EMLDMAWR:
1737 #if(0)
1738                     device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1739 #endif
1740                     if (ch->run != 1) {
1741                               error = -1;
1742                               goto fail;
1743                     }
1744                     ch->emldma(ch);
1745                     break;
1746           case PCMTRIG_EMLDMARD:
1747 #if(0)
1748                     device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1749 #endif
1750                     if (ch->run != 1) {
1751                               error = -1;
1752                               goto fail;
1753                     }
1754                     ch->emldma(ch);
1755                     break;
1756           case PCMTRIG_ABORT:
1757                     if (ch->run) {
1758 #if(0)
1759                     device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1760 #endif
1761                     ch->run = 0;
1762                     sc->run[slot]--;
1763                     if (ch->dir == PCMDIR_PLAY)
1764                               envy24ht_mutevolume(sc, ch->num);
1765                     if (sc->run[slot] == 0) {
1766                               envy24ht_stop(sc, ch->dir);
1767                               sc->intr[slot] = 0;
1768                     }
1769 /*                  else if (ch->blk == sc->blk[slot]) {
1770                               sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1771                               for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1772                                         if (sc->chan[i].dir == ch->dir &&
1773                                             sc->chan[i].run == 1 &&
1774                                             sc->chan[i].blk < sc->blk[slot])
1775                                                   sc->blk[slot] = sc->chan[i].blk;
1776                               }
1777                               if (ch->blk != sc->blk[slot])
1778                                         envy24ht_updintr(sc, ch->dir);
1779                     }*/
1780                     }
1781                     break;
1782           }
1783 fail:
1784           snd_mtxunlock(sc->lock);
1785           return (error);
1786 }
1787 
1788 static u_int32_t
envy24htchan_getptr(kobj_t obj,void * data)1789 envy24htchan_getptr(kobj_t obj, void *data)
1790 {
1791           struct sc_chinfo *ch = data;
1792           struct sc_info *sc = ch->parent;
1793           u_int32_t ptr, rtn;
1794 
1795 #if(0)
1796           device_printf(sc->dev, "envy24htchan_getptr()\n");
1797 #endif
1798           snd_mtxlock(sc->lock);
1799           ptr = envy24ht_gethwptr(sc, ch->dir);
1800           rtn = ptr * ch->unit;
1801           snd_mtxunlock(sc->lock);
1802 
1803 #if(0)
1804           device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1805               rtn);
1806 #endif
1807           return rtn;
1808 }
1809 
1810 static struct pcmchan_caps *
envy24htchan_getcaps(kobj_t obj,void * data)1811 envy24htchan_getcaps(kobj_t obj, void *data)
1812 {
1813           struct sc_chinfo *ch = data;
1814           struct sc_info *sc = ch->parent;
1815           struct pcmchan_caps *rtn;
1816 
1817 #if(0)
1818           device_printf(sc->dev, "envy24htchan_getcaps()\n");
1819 #endif
1820           snd_mtxlock(sc->lock);
1821           if (ch->dir == PCMDIR_PLAY) {
1822                     if (sc->run[0] == 0)
1823                               rtn = &envy24ht_playcaps;
1824                     else
1825                               rtn = &sc->caps[0];
1826           }
1827           else {
1828                     if (sc->run[1] == 0)
1829                               rtn = &envy24ht_reccaps;
1830                     else
1831                               rtn = &sc->caps[1];
1832           }
1833           snd_mtxunlock(sc->lock);
1834 
1835           return rtn;
1836 }
1837 
1838 static kobj_method_t envy24htchan_methods[] = {
1839           KOBJMETHOD(channel_init,                envy24htchan_init),
1840           KOBJMETHOD(channel_free,                envy24htchan_free),
1841           KOBJMETHOD(channel_setformat,           envy24htchan_setformat),
1842           KOBJMETHOD(channel_setspeed,            envy24htchan_setspeed),
1843           KOBJMETHOD(channel_setblocksize,        envy24htchan_setblocksize),
1844           KOBJMETHOD(channel_trigger,             envy24htchan_trigger),
1845           KOBJMETHOD(channel_getptr,              envy24htchan_getptr),
1846           KOBJMETHOD(channel_getcaps,             envy24htchan_getcaps),
1847           KOBJMETHOD_END
1848 };
1849 CHANNEL_DECLARE(envy24htchan);
1850 
1851 /* -------------------------------------------------------------------- */
1852 
1853 /* mixer interface */
1854 
1855 static int
envy24htmixer_init(struct snd_mixer * m)1856 envy24htmixer_init(struct snd_mixer *m)
1857 {
1858           struct sc_info *sc = mix_getdevinfo(m);
1859 
1860 #if(0)
1861           device_printf(sc->dev, "envy24htmixer_init()\n");
1862 #endif
1863           if (sc == NULL)
1864                     return -1;
1865 
1866           /* set volume control rate */
1867           snd_mtxlock(sc->lock);
1868 #if 0
1869           envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1870 #endif
1871 
1872           pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1873 
1874           mix_setdevs(m, ENVY24HT_MIX_MASK);
1875           mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1876 
1877           snd_mtxunlock(sc->lock);
1878 
1879           return 0;
1880 }
1881 
1882 static int
envy24htmixer_reinit(struct snd_mixer * m)1883 envy24htmixer_reinit(struct snd_mixer *m)
1884 {
1885           struct sc_info *sc = mix_getdevinfo(m);
1886 
1887           if (sc == NULL)
1888                     return -1;
1889 #if(0)
1890           device_printf(sc->dev, "envy24htmixer_reinit()\n");
1891 #endif
1892 
1893           return 0;
1894 }
1895 
1896 static int
envy24htmixer_uninit(struct snd_mixer * m)1897 envy24htmixer_uninit(struct snd_mixer *m)
1898 {
1899           struct sc_info *sc = mix_getdevinfo(m);
1900 
1901           if (sc == NULL)
1902                     return -1;
1903 #if(0)
1904           device_printf(sc->dev, "envy24htmixer_uninit()\n");
1905 #endif
1906 
1907           return 0;
1908 }
1909 
1910 static int
envy24htmixer_set(struct snd_mixer * m,unsigned dev,unsigned left,unsigned right)1911 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1912 {
1913           struct sc_info *sc = mix_getdevinfo(m);
1914           int ch = envy24ht_mixmap[dev];
1915           int hwch;
1916           int i;
1917 
1918           if (sc == NULL)
1919                     return -1;
1920           if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1921                     return -1;
1922           if (dev != 0 && ch == -1)
1923                     return -1;
1924           hwch = envy24ht_chanmap[ch];
1925 #if(0)
1926           device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1927               dev, left, right);
1928 #endif
1929 
1930           snd_mtxlock(sc->lock);
1931           if (dev == 0) {
1932                     for (i = 0; i < sc->dacn; i++) {
1933                               sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1934                     }
1935           }
1936           else {
1937                     /* set volume value for hardware */
1938                     if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1939                               sc->left[hwch] = ENVY24HT_VOL_MUTE;
1940                     if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1941                               sc->right[hwch] = ENVY24HT_VOL_MUTE;
1942 
1943                     /* set volume for record channel and running play channel */
1944                     if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1945                               envy24ht_setvolume(sc, hwch);
1946           }
1947           snd_mtxunlock(sc->lock);
1948 
1949           return right << 8 | left;
1950 }
1951 
1952 static u_int32_t
envy24htmixer_setrecsrc(struct snd_mixer * m,u_int32_t src)1953 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1954 {
1955           struct sc_info *sc = mix_getdevinfo(m);
1956           int ch = envy24ht_mixmap[src];
1957 #if(0)
1958           device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1959 #endif
1960 
1961           if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1962                     sc->src = ch;
1963           return src;
1964 }
1965 
1966 static kobj_method_t envy24htmixer_methods[] = {
1967           KOBJMETHOD(mixer_init,                  envy24htmixer_init),
1968           KOBJMETHOD(mixer_reinit,      envy24htmixer_reinit),
1969           KOBJMETHOD(mixer_uninit,      envy24htmixer_uninit),
1970           KOBJMETHOD(mixer_set,                   envy24htmixer_set),
1971           KOBJMETHOD(mixer_setrecsrc,   envy24htmixer_setrecsrc),
1972           KOBJMETHOD_END
1973 };
1974 MIXER_DECLARE(envy24htmixer);
1975 
1976 /* -------------------------------------------------------------------- */
1977 
1978 /* The interrupt handler */
1979 static void
envy24ht_intr(void * p)1980 envy24ht_intr(void *p)
1981 {
1982           struct sc_info *sc = (struct sc_info *)p;
1983           struct sc_chinfo *ch;
1984           u_int32_t ptr, dsize, feed;
1985           int i;
1986 
1987 #if(0)
1988           device_printf(sc->dev, "envy24ht_intr()\n");
1989 #endif
1990           snd_mtxlock(sc->lock);
1991           if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1992 #if(0)
1993                     device_printf(sc->dev, "envy24ht_intr(): play\n");
1994 #endif
1995                     dsize = sc->psize / 4;
1996                     ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
1997 #if(0)
1998                     device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
1999 #endif
2000                     ptr -= ptr % sc->blk[0];
2001                     feed = (ptr + dsize - sc->intr[0]) % dsize;
2002 #if(0)
2003                     printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2004 #endif
2005                     for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
2006                               ch = &sc->chan[i];
2007 #if(0)
2008                               if (ch->run)
2009                                         device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
2010 #endif
2011                               if (ch->run && ch->blk <= feed) {
2012                                         snd_mtxunlock(sc->lock);
2013                                         chn_intr(ch->channel);
2014                                         snd_mtxlock(sc->lock);
2015                               }
2016                     }
2017                     sc->intr[0] = ptr;
2018                     envy24ht_updintr(sc, PCMDIR_PLAY);
2019           }
2020           if (envy24ht_checkintr(sc, PCMDIR_REC)) {
2021 #if(0)
2022                     device_printf(sc->dev, "envy24ht_intr(): rec\n");
2023 #endif
2024                     dsize = sc->rsize / 4;
2025                     ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
2026                     ptr -= ptr % sc->blk[1];
2027                     feed = (ptr + dsize - sc->intr[1]) % dsize;
2028                     for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
2029                               ch = &sc->chan[i];
2030                               if (ch->run && ch->blk <= feed) {
2031                                         snd_mtxunlock(sc->lock);
2032                                         chn_intr(ch->channel);
2033                                         snd_mtxlock(sc->lock);
2034                               }
2035                     }
2036                     sc->intr[1] = ptr;
2037                     envy24ht_updintr(sc, PCMDIR_REC);
2038           }
2039           snd_mtxunlock(sc->lock);
2040 
2041           return;
2042 }
2043 
2044 /*
2045  * Probe and attach the card
2046  */
2047 
2048 static int
envy24ht_pci_probe(device_t dev)2049 envy24ht_pci_probe(device_t dev)
2050 {
2051           u_int16_t sv, sd;
2052           int i;
2053 
2054 #if(0)
2055           printf("envy24ht_pci_probe()\n");
2056 #endif
2057           if (pci_get_device(dev) == PCID_ENVY24HT &&
2058               pci_get_vendor(dev) == PCIV_ENVY24) {
2059                     sv = pci_get_subvendor(dev);
2060                     sd = pci_get_subdevice(dev);
2061                     for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2062                               if (cfg_table[i].subvendor == sv &&
2063                                   cfg_table[i].subdevice == sd) {
2064                                         break;
2065                               }
2066                     }
2067                     device_set_desc(dev, cfg_table[i].name);
2068 #if(0)
2069                     printf("envy24ht_pci_probe(): return 0\n");
2070 #endif
2071                     return 0;
2072           }
2073           else {
2074 #if(0)
2075                     printf("envy24ht_pci_probe(): return ENXIO\n");
2076 #endif
2077                     return ENXIO;
2078           }
2079 }
2080 
2081 static void
envy24ht_dmapsetmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)2082 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2083 {
2084           struct sc_info *sc = arg;
2085 
2086           sc->paddr = segs->ds_addr;
2087 #if(0)
2088           device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2089           if (bootverbose) {
2090                     printf("envy24ht(play): setmap %lx, %lx; ",
2091                         (unsigned long)segs->ds_addr,
2092                         (unsigned long)segs->ds_len);
2093           }
2094 #endif
2095           envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, (uint32_t)segs->ds_addr, 4);
2096           envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2097 }
2098 
2099 static void
envy24ht_dmarsetmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)2100 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2101 {
2102           struct sc_info *sc = arg;
2103 
2104           sc->raddr = segs->ds_addr;
2105 #if(0)
2106           device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2107           if (bootverbose) {
2108                     printf("envy24ht(record): setmap %lx, %lx; ",
2109                         (unsigned long)segs->ds_addr,
2110                         (unsigned long)segs->ds_len);
2111           }
2112 #endif
2113           envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, (uint32_t)segs->ds_addr, 4);
2114           envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2115 }
2116 
2117 static void
envy24ht_dmafree(struct sc_info * sc)2118 envy24ht_dmafree(struct sc_info *sc)
2119 {
2120 #if(0)
2121           device_printf(sc->dev, "envy24ht_dmafree():");
2122           printf(" sc->raddr(0x%08x)", (u_int32_t)sc->raddr);
2123           printf(" sc->paddr(0x%08x)", (u_int32_t)sc->paddr);
2124           if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2125           else printf(" sc->rbuf(null)");
2126           if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2127           else printf(" sc->pbuf(null)\n");
2128 #endif
2129 #if(0)
2130           if (sc->raddr)
2131                     bus_dmamap_unload(sc->dmat, sc->rmap);
2132           if (sc->paddr)
2133                     bus_dmamap_unload(sc->dmat, sc->pmap);
2134           if (sc->rbuf)
2135                     bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2136           if (sc->pbuf)
2137                     bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2138 #else
2139           bus_dmamap_unload(sc->dmat, sc->rmap);
2140           bus_dmamap_unload(sc->dmat, sc->pmap);
2141           bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2142           bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2143 #endif
2144 
2145           sc->raddr = sc->paddr = 0;
2146           sc->pbuf = NULL;
2147           sc->rbuf = NULL;
2148 
2149           return;
2150 }
2151 
2152 static int
envy24ht_dmainit(struct sc_info * sc)2153 envy24ht_dmainit(struct sc_info *sc)
2154 {
2155 
2156 #if(0)
2157           device_printf(sc->dev, "envy24ht_dmainit()\n");
2158 #endif
2159           /* init values */
2160           sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2161           sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2162           sc->pbuf = NULL;
2163           sc->rbuf = NULL;
2164           sc->paddr = sc->raddr = 0;
2165           sc->blk[0] = sc->blk[1] = 0;
2166 
2167           /* allocate DMA buffer */
2168 #if(0)
2169           device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2170 #endif
2171           if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2172                     goto bad;
2173 #if(0)
2174           device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2175 #endif
2176           if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2177                     goto bad;
2178 #if(0)
2179           device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2180 #endif
2181           if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, BUS_DMA_NOWAIT))
2182                     goto bad;
2183 #if(0)
2184           device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2185 #endif
2186           if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, BUS_DMA_NOWAIT))
2187                     goto bad;
2188           bzero(sc->pbuf, sc->psize);
2189           bzero(sc->rbuf, sc->rsize);
2190 
2191           return 0;
2192  bad:
2193           envy24ht_dmafree(sc);
2194           return ENOSPC;
2195 }
2196 
2197 static void
envy24ht_putcfg(struct sc_info * sc)2198 envy24ht_putcfg(struct sc_info *sc)
2199 {
2200           device_printf(sc->dev, "system configuration\n");
2201           kprintf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2202               sc->cfg->subvendor, sc->cfg->subdevice);
2203           kprintf("  XIN2 Clock Source: ");
2204           switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2205           case 0x00:
2206                     kprintf("24.576MHz(96kHz*256)\n");
2207                     break;
2208           case 0x40:
2209                     kprintf("49.152MHz(192kHz*256)\n");
2210                     break;
2211           case 0x80:
2212                     kprintf("reserved\n");
2213                     break;
2214           default:
2215                     kprintf("illegal system setting\n");
2216           }
2217           kprintf("  MPU-401 UART(s) #: ");
2218           if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2219                     kprintf("1\n");
2220           else
2221                     kprintf("not implemented\n");
2222         switch (sc->adcn) {
2223         case 0x01:
2224           case 0x02:
2225                 kprintf("  ADC #: ");
2226                 kprintf("%d\n", sc->adcn);
2227                 break;
2228         case 0x03:
2229                 kprintf("  ADC #: ");
2230                 kprintf("%d", 1);
2231                 kprintf(" and SPDIF receiver connected\n");
2232                 break;
2233         default:
2234                 kprintf("  no physical inputs\n");
2235         }
2236           kprintf("  DAC #: ");
2237           kprintf("%d\n", sc->dacn);
2238           kprintf("  Multi-track converter type: ");
2239           if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2240                     kprintf("AC'97(SDATA_OUT:");
2241                     if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2242                               kprintf("packed");
2243                     else
2244                               kprintf("split");
2245                     kprintf(")\n");
2246           }
2247           else {
2248                     kprintf("I2S(");
2249                     if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2250                               kprintf("with volume, ");
2251                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2252                         kprintf("192KHz support, ");
2253                 else
2254                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2255                         kprintf("192KHz support, ");
2256                 else
2257                         kprintf("48KHz support, ");
2258                     switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2259                     case ENVY24HT_CCSM_I2S_16BIT:
2260                               kprintf("16bit resolution, ");
2261                               break;
2262                     case ENVY24HT_CCSM_I2S_18BIT:
2263                               kprintf("18bit resolution, ");
2264                               break;
2265                     case ENVY24HT_CCSM_I2S_20BIT:
2266                               kprintf("20bit resolution, ");
2267                               break;
2268                     case ENVY24HT_CCSM_I2S_24BIT:
2269                               kprintf("24bit resolution, ");
2270                               break;
2271                     }
2272                     kprintf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2273           }
2274           kprintf("  S/PDIF(IN/OUT): ");
2275           if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2276                     kprintf("1/");
2277           else
2278                     kprintf("0/");
2279           if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2280                     kprintf("1 ");
2281           else
2282                     kprintf("0 ");
2283           if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2284                     kprintf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2285           kprintf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2286               sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2287 }
2288 
2289 static int
envy24ht_init(struct sc_info * sc)2290 envy24ht_init(struct sc_info *sc)
2291 {
2292           u_int32_t data;
2293 #if(0)
2294           int rtn;
2295 #endif
2296           int i;
2297           u_int32_t sv, sd;
2298 
2299 
2300 #if(0)
2301           device_printf(sc->dev, "envy24ht_init()\n");
2302 #endif
2303 
2304           /* reset chip */
2305 #if 0
2306           envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2307           DELAY(200);
2308           envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2309           DELAY(200);
2310 
2311           /* legacy hardware disable */
2312           data = pci_read_config(sc->dev, PCIR_LAC, 2);
2313           data |= PCIM_LAC_DISABLE;
2314           pci_write_config(sc->dev, PCIR_LAC, data, 2);
2315 #endif
2316 
2317           /* check system configuration */
2318           sc->cfg = NULL;
2319           for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2320                     /* 1st: search configuration from table */
2321                     sv = pci_get_subvendor(sc->dev);
2322                     sd = pci_get_subdevice(sc->dev);
2323                     if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2324 #if(0)
2325                               device_printf(sc->dev, "Set configuration from table\n");
2326 #endif
2327                               sc->cfg = &cfg_table[i];
2328                               break;
2329                     }
2330           }
2331           if (sc->cfg == NULL) {
2332                     /* 2nd: read configuration from table */
2333                     sc->cfg = envy24ht_rom2cfg(sc);
2334           }
2335           sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2336           sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2337 
2338           if (1 /* bootverbose */) {
2339                     envy24ht_putcfg(sc);
2340           }
2341 
2342           /* set system configuration */
2343           envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2344           envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2345           envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2346           envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2347           envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2348           envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2349           envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2350 
2351           if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2352                     envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2353                     envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2354                     envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2355           }
2356 
2357           for (i = 0; i < sc->adcn; i++) {
2358                     sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2359                     sc->cfg->codec->init(sc->adc[i]);
2360           }
2361           for (i = 0; i < sc->dacn; i++) {
2362                     sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2363                     sc->cfg->codec->init(sc->dac[i]);
2364           }
2365 
2366           /* initialize DMA buffer */
2367 #if(0)
2368           device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2369 #endif
2370           if (envy24ht_dmainit(sc))
2371                     return ENOSPC;
2372 
2373           /* initialize status */
2374           sc->run[0] = sc->run[1] = 0;
2375           sc->intr[0] = sc->intr[1] = 0;
2376           sc->speed = 0;
2377           sc->caps[0].fmtlist = envy24ht_playfmt;
2378           sc->caps[1].fmtlist = envy24ht_recfmt;
2379 
2380           /* set channel router */
2381 #if 0
2382           envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2383           envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2384           envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2385 #endif
2386 
2387           /* set macro interrupt mask */
2388           data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2389           envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2390           data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2391 #if(0)
2392           device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2393 #endif
2394 
2395           return 0;
2396 }
2397 
2398 static int
envy24ht_alloc_resource(struct sc_info * sc)2399 envy24ht_alloc_resource(struct sc_info *sc)
2400 {
2401           /* allocate I/O port resource */
2402           sc->csid = PCIR_CCS;
2403           sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2404               &sc->csid, 0, ~0, 1, RF_ACTIVE);
2405           sc->mtid = ENVY24HT_PCIR_MT;
2406           sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2407               &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2408           if (!sc->cs || !sc->mt) {
2409                     device_printf(sc->dev, "unable to map IO port space\n");
2410                     return ENXIO;
2411           }
2412           sc->cst = rman_get_bustag(sc->cs);
2413           sc->csh = rman_get_bushandle(sc->cs);
2414           sc->mtt = rman_get_bustag(sc->mt);
2415           sc->mth = rman_get_bushandle(sc->mt);
2416 #if(0)
2417           device_printf(sc->dev,
2418               "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2419               pci_read_config(sc->dev, PCIR_CCS, 4),
2420               pci_read_config(sc->dev, PCIR_MT, 4));
2421 #endif
2422 
2423           /* allocate interrupt resource */
2424           sc->irqid = 0;
2425           sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2426                                          0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2427           if (!sc->irq ||
2428               snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24ht_intr, sc, &sc->ih)) {
2429                     device_printf(sc->dev, "unable to map interrupt\n");
2430                     return ENXIO;
2431           }
2432 
2433           /* allocate DMA resource */
2434           if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2435               /*alignment*/4,
2436               /*boundary*/0,
2437               /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
2438               /*highaddr*/BUS_SPACE_MAXADDR,
2439               /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2440               /*nsegments*/1, /*maxsegsz*/0x3ffff,
2441               /*flags*/0,
2442               &sc->dmat) != 0) {
2443                     device_printf(sc->dev, "unable to create dma tag\n");
2444                     return ENXIO;
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 = kmalloc(sizeof(*sc), M_ENVY24HT, M_WAITOK | M_ZERO)) == 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           ksnprintf(status, SND_STATUSLEN,
2509               "at io 0x%lx:%ld,0x%lx:%ld irq %ld",
2510               rman_get_start(sc->cs),
2511               rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2512               rman_get_start(sc->mt),
2513               rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2514               rman_get_start(sc->irq));
2515           pcm_setstatus(dev, status);
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           kfree(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           kfree(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           PCM_SOFTC_SIZE,
2591 };
2592 
2593 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, NULL, NULL);
2594 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2595 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2596 MODULE_VERSION(snd_envy24ht, 1);
2597