Line data Source code
1 : /* $OpenBSD: envy.c,v 1.73 2018/09/03 05:37:32 miko Exp $ */
2 : /*
3 : * Copyright (c) 2007 Alexandre Ratchov <alex@caoua.org>
4 : *
5 : * Permission to use, copy, modify, and distribute this software for any
6 : * purpose with or without fee is hereby granted, provided that the above
7 : * copyright notice and this permission notice appear in all copies.
8 : *
9 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 : */
17 :
18 : /*
19 : * TODO:
20 : *
21 : * - add nspdin, nspdout, to struct envy_card
22 : *
23 : * - use eeprom version rather isht flag
24 : *
25 : * - implement HT mixer, midi uart, spdif, init ADC/DACs for >48kHz modes
26 : *
27 : */
28 :
29 : #include "midi.h"
30 : #include <sys/param.h>
31 : #include <sys/systm.h>
32 : #include <sys/device.h>
33 : #include <sys/audioio.h>
34 : #include <sys/malloc.h>
35 : #include <sys/kernel.h>
36 : #include <dev/audio_if.h>
37 : #include <dev/midi_if.h>
38 : #include <dev/ic/ac97.h>
39 : #include <dev/pci/pcivar.h>
40 : #include <dev/pci/pcidevs.h>
41 : #include <dev/pci/envyvar.h>
42 : #include <dev/pci/envyreg.h>
43 : #include <machine/bus.h>
44 : #include <uvm/uvm.h>
45 :
46 : #ifdef ENVY_DEBUG
47 : #define DPRINTF(...) do { if (envydebug) printf(__VA_ARGS__); } while(0)
48 : #define DPRINTFN(n, ...) do { if (envydebug > (n)) printf(__VA_ARGS__); } while(0)
49 : int envydebug = 1;
50 : #else
51 : #define DPRINTF(...) do {} while(0)
52 : #define DPRINTFN(n, ...) do {} while(0)
53 : #endif
54 : #define DEVNAME(sc) ((sc)->dev.dv_xname)
55 :
56 : int envymatch(struct device *, void *, void *);
57 : void envyattach(struct device *, struct device *, void *);
58 : int envydetach(struct device *, int);
59 : int envyactivate(struct device *, int);
60 :
61 : int envy_ccs_read(struct envy_softc *, int);
62 : void envy_ccs_write(struct envy_softc *, int, int);
63 : int envy_mt_read_1(struct envy_softc *, int);
64 : void envy_mt_write_1(struct envy_softc *, int, int);
65 : int envy_mt_read_2(struct envy_softc *, int);
66 : void envy_mt_write_2(struct envy_softc *, int, int);
67 : int envy_mt_read_4(struct envy_softc *, int);
68 : void envy_mt_write_4(struct envy_softc *, int, int);
69 : int envy_cci_read(struct envy_softc *, int);
70 : void envy_cci_write(struct envy_softc *, int, int);
71 : void envy_i2c_wait(struct envy_softc *);
72 : int envy_i2c_read(struct envy_softc *, int, int);
73 : void envy_i2c_write(struct envy_softc *, int, int, int);
74 : int envy_gpio_getstate(struct envy_softc *);
75 : void envy_gpio_setstate(struct envy_softc *, int);
76 : int envy_gpio_getmask(struct envy_softc *);
77 : void envy_gpio_setmask(struct envy_softc *, int);
78 : int envy_gpio_getdir(struct envy_softc *);
79 : void envy_gpio_setdir(struct envy_softc *, int);
80 : void envy_gpio_i2c_start_bit(struct envy_softc *, int, int);
81 : void envy_gpio_i2c_stop_bit(struct envy_softc *, int, int);
82 : void envy_gpio_i2c_byte_out(struct envy_softc *, int, int, int);
83 : int envy_eeprom_gpioxxx(struct envy_softc *, int);
84 : void envy_midi_wait(struct envy_softc *);
85 : void envy_reset(struct envy_softc *);
86 : int envy_codec_read(struct envy_softc *, int, int);
87 : void envy_codec_write(struct envy_softc *, int, int, int);
88 : void envy_pintr(struct envy_softc *);
89 : int envy_intr(void *);
90 :
91 : int envy_lineout_getsrc(struct envy_softc *, int);
92 : void envy_lineout_setsrc(struct envy_softc *, int, int);
93 : int envy_spdout_getsrc(struct envy_softc *, int);
94 : void envy_spdout_setsrc(struct envy_softc *, int, int);
95 : void envy_mon_getvol(struct envy_softc *, int, int, int *);
96 : void envy_mon_setvol(struct envy_softc *, int, int, int);
97 :
98 : int envy_open(void *, int);
99 : void envy_close(void *);
100 : void *envy_allocm(void *, int, size_t, int, int);
101 : void envy_freem(void *, void *, int);
102 : int envy_set_params(void *, int, int, struct audio_params *,
103 : struct audio_params *);
104 : int envy_round_blocksize(void *, int);
105 : int envy_trigger_output(void *, void *, void *, int,
106 : void (*)(void *), void *, struct audio_params *);
107 : int envy_trigger_input(void *, void *, void *, int,
108 : void (*)(void *), void *, struct audio_params *);
109 : int envy_halt_output(void *);
110 : int envy_halt_input(void *);
111 : int envy_query_devinfo(void *, struct mixer_devinfo *);
112 : int envy_get_port(void *, struct mixer_ctrl *);
113 : int envy_set_port(void *, struct mixer_ctrl *);
114 : int envy_get_props(void *);
115 : #if NMIDI > 0
116 : int envy_midi_open(void *, int, void (*)(void *, int),
117 : void (*)(void *), void *);
118 : void envy_midi_close(void *);
119 : int envy_midi_output(void *, int);
120 : void envy_midi_getinfo(void *, struct midi_info *);
121 : #endif
122 :
123 : int envy_ac97_wait(struct envy_softc *);
124 : int envy_ac97_attach_codec(void *, struct ac97_codec_if *);
125 : int envy_ac97_read_codec(void *, u_int8_t, u_int16_t *);
126 : int envy_ac97_write_codec(void *, u_int8_t, u_int16_t);
127 : void envy_ac97_reset_codec(void *);
128 : enum ac97_host_flags envy_ac97_flags_codec(void *);
129 :
130 : void delta_init(struct envy_softc *);
131 : void delta_codec_write(struct envy_softc *, int, int, int);
132 :
133 : void ap192k_init(struct envy_softc *);
134 : void ap192k_codec_write(struct envy_softc *, int, int, int);
135 :
136 : void ewx_codec_write(struct envy_softc *, int, int, int);
137 :
138 : void revo51_init(struct envy_softc *);
139 : void revo51_codec_write(struct envy_softc *, int, int, int);
140 :
141 : void envy_ac97_init(struct envy_softc *);
142 : void dynex_sc51_init(struct envy_softc *);
143 :
144 : void julia_init(struct envy_softc *);
145 : void julia_codec_write(struct envy_softc *, int, int, int);
146 :
147 : void unkenvy_init(struct envy_softc *);
148 : void unkenvy_codec_write(struct envy_softc *, int, int, int);
149 : int unkenvy_codec_ndev(struct envy_softc *);
150 :
151 : int ak4524_dac_ndev(struct envy_softc *);
152 : void ak4524_dac_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
153 : void ak4524_dac_get(struct envy_softc *, struct mixer_ctrl *, int);
154 : int ak4524_dac_set(struct envy_softc *, struct mixer_ctrl *, int);
155 : int ak4524_adc_ndev(struct envy_softc *);
156 : void ak4524_adc_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
157 : void ak4524_adc_get(struct envy_softc *, struct mixer_ctrl *, int);
158 : int ak4524_adc_set(struct envy_softc *, struct mixer_ctrl *, int);
159 :
160 : int ak4358_dac_ndev(struct envy_softc *);
161 : void ak4358_dac_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
162 : void ak4358_dac_get(struct envy_softc *, struct mixer_ctrl *, int);
163 : int ak4358_dac_set(struct envy_softc *, struct mixer_ctrl *, int);
164 :
165 : int ak5365_adc_ndev(struct envy_softc *);
166 : void ak5365_adc_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
167 : void ak5365_adc_get(struct envy_softc *, struct mixer_ctrl *, int);
168 : int ak5365_adc_set(struct envy_softc *, struct mixer_ctrl *, int);
169 :
170 : struct cfattach envy_ca = {
171 : sizeof(struct envy_softc), envymatch, envyattach, envydetach,
172 : envyactivate
173 : };
174 :
175 : struct cfdriver envy_cd = {
176 : NULL, "envy", DV_DULL
177 : };
178 :
179 : struct audio_hw_if envy_hw_if = {
180 : envy_open, /* open */
181 : envy_close, /* close */
182 : envy_set_params, /* set_params */
183 : envy_round_blocksize, /* round_blocksize */
184 : NULL, /* commit_settings */
185 : NULL, /* init_output */
186 : NULL, /* init_input */
187 : NULL, /* start_output */
188 : NULL, /* start_input */
189 : envy_halt_output, /* halt_output */
190 : envy_halt_input, /* halt_input */
191 : NULL, /* speaker_ctl */
192 : NULL, /* setfd */
193 : envy_set_port, /* set_port */
194 : envy_get_port, /* get_port */
195 : envy_query_devinfo, /* query_devinfo */
196 : envy_allocm, /* malloc */
197 : envy_freem, /* free */
198 : NULL, /* round_buffersize */
199 : envy_get_props, /* get_props */
200 : envy_trigger_output, /* trigger_output */
201 : envy_trigger_input /* trigger_input */
202 : };
203 :
204 : #if NMIDI > 0
205 : struct midi_hw_if envy_midi_hw_if = {
206 : envy_midi_open,
207 : envy_midi_close,
208 : envy_midi_output,
209 : NULL, /* flush */
210 : envy_midi_getinfo,
211 : NULL /* ioctl */
212 : };
213 : #endif
214 :
215 : struct pci_matchid envy_matchids[] = {
216 : { PCI_VENDOR_ICENSEMBLE, PCI_PRODUCT_ICENSEMBLE_ICE1712 },
217 : { PCI_VENDOR_ICENSEMBLE, PCI_PRODUCT_ICENSEMBLE_VT172x }
218 : };
219 :
220 : /*
221 : * correspondence between rates (in frames per second)
222 : * and values of rate register
223 : */
224 : struct {
225 : int rate, reg;
226 : } envy_rates[] = {
227 : { 8000, 0x6}, { 9600, 0x3}, {11025, 0xa}, {12000, 2}, {16000, 5},
228 : {22050, 0x9}, {24000, 0x1}, {32000, 0x4}, {44100, 8}, {48000, 0},
229 : {64000, 0xf}, {88200, 0xb}, {96000, 0x7}, {-1, -1}
230 : };
231 :
232 : /*
233 : * ESI Julia cards don't have EEPROM, use this copy
234 : */
235 : static unsigned char julia_eeprom[ENVY_EEPROM_MAXSZ] = {
236 : /* gpio mask/dir/state is from linux */
237 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 : 0x20, 0x80, 0xf8, 0xc3,
239 : 0x9f, 0xff, 0x7f,
240 : 0x90, 0xff, 0x7f,
241 : 0x66, 0x00, 0x00
242 : };
243 :
244 : struct envy_codec ak4524_dac = {
245 : "ak4524 dac", ak4524_dac_ndev, ak4524_dac_devinfo, ak4524_dac_get, ak4524_dac_set
246 : }, ak4524_adc = {
247 : "ak4524 adc", ak4524_adc_ndev, ak4524_adc_devinfo, ak4524_adc_get, ak4524_adc_set
248 : }, ak4358_dac = {
249 : "ak4358 dac", ak4358_dac_ndev, ak4358_dac_devinfo, ak4358_dac_get, ak4358_dac_set
250 : }, ak5365_adc = {
251 : "ak5365 adc", ak5365_adc_ndev, ak5365_adc_devinfo, ak5365_adc_get, ak5365_adc_set
252 : }, unkenvy_codec = {
253 : "unknown codec", unkenvy_codec_ndev, NULL, NULL, NULL
254 : };
255 :
256 : /*
257 : * array with vendor/product sub-IDs to card info
258 : */
259 : struct envy_card envy_cards[] = {
260 : {
261 : PCI_ID_CODE(0x1412, 0xd630),
262 : "M-Audio Delta 1010",
263 : 8, &ak4524_adc, 8, &ak4524_dac, 1,
264 : delta_init,
265 : delta_codec_write,
266 : NULL
267 : }, {
268 : PCI_ID_CODE(0x1412, 0xd632),
269 : "M-Audio Delta 66",
270 : 4, &ak4524_adc, 4, &ak4524_dac, 0,
271 : delta_init,
272 : delta_codec_write,
273 : NULL
274 : }, {
275 : #define ENVY_SUBID_DELTA44 (PCI_ID_CODE(0x1412, 0xd633))
276 : PCI_ID_CODE(0x1412, 0xd633),
277 : "M-Audio Delta 44",
278 : 4, &ak4524_adc, 4, &ak4524_dac, 0,
279 : delta_init,
280 : delta_codec_write,
281 : NULL
282 : }, {
283 : PCI_ID_CODE(0x1412, 0xd63b),
284 : "M-Audio Delta 1010LT",
285 : 8, &ak4524_adc, 8, &ak4524_dac, 1,
286 : delta_init,
287 : delta_codec_write,
288 : NULL
289 : }, {
290 : PCI_ID_CODE(0x1412, 0xd634),
291 : "M-Audio Audiophile 2496",
292 : 2, &ak4524_adc, 2, &ak4524_dac, 1,
293 : delta_init,
294 : delta_codec_write,
295 : NULL
296 : }, {
297 : PCI_ID_CODE(0x153b, 0x1130),
298 : "Terratec EWX 24/96",
299 : 2, &ak4524_adc, 2, &ak4524_dac, 1,
300 : delta_init,
301 : ewx_codec_write,
302 : NULL
303 : }, {
304 : 0,
305 : "unknown 1712-based card",
306 : 8, &unkenvy_codec, 8, &unkenvy_codec, 1,
307 : unkenvy_init,
308 : unkenvy_codec_write
309 : }
310 : }, envy_cards_ht[] = {
311 : {
312 : PCI_ID_CODE(0x3031, 0x4553),
313 : "ESI Julia",
314 : 2, &unkenvy_codec, 2, &ak4358_dac, 1,
315 : julia_init,
316 : julia_codec_write,
317 : julia_eeprom
318 : }, {
319 : PCI_ID_CODE(0x1412, 0x3632),
320 : "M-Audio Audiophile 192k",
321 : 2, &unkenvy_codec, 2, &ak4358_dac, 1,
322 : ap192k_init,
323 : ap192k_codec_write
324 : }, {
325 : PCI_ID_CODE(0x1412, 0x3631),
326 : "M-Audio Revolution 5.1",
327 : 2, &ak5365_adc, 6, &ak4358_dac, 1,
328 : revo51_init,
329 : revo51_codec_write
330 : }, {
331 : PCI_ID_CODE(0x1412, 0x2403),
332 : "VIA Tremor 5.1",
333 : 2, &unkenvy_codec, 6, &unkenvy_codec, 1,
334 : envy_ac97_init,
335 : unkenvy_codec_write
336 : }, {
337 : PCI_ID_CODE(0x14c3, 0x1705),
338 : "Dynex DX-SC51",
339 : 2, &unkenvy_codec, 6, &unkenvy_codec, 0,
340 : dynex_sc51_init,
341 : unkenvy_codec_write
342 : }, {
343 : 0,
344 : "unknown 1724-based card",
345 : 2, &unkenvy_codec, 8, &unkenvy_codec, 1,
346 : unkenvy_init,
347 : unkenvy_codec_write
348 : }
349 : };
350 :
351 :
352 : /*
353 : * M-Audio Delta specific code
354 : */
355 :
356 : void
357 0 : delta_init(struct envy_softc *sc)
358 : {
359 : int dev;
360 :
361 0 : for (dev = 0; dev < sc->card->noch / 2; dev++) {
362 0 : envy_codec_write(sc, dev, AK4524_RST, 0x0);
363 0 : delay(300);
364 0 : envy_codec_write(sc, dev, AK4524_RST,
365 : AK4524_RST_AD | AK4524_RST_DA);
366 0 : envy_codec_write(sc, dev, AK4524_FMT,
367 : AK4524_FMT_IIS24);
368 0 : sc->shadow[dev][AK4524_DEEMVOL] = AK4524_DEEM_OFF;
369 0 : sc->shadow[dev][AK4524_ADC_GAIN0] = 0x7f;
370 0 : sc->shadow[dev][AK4524_ADC_GAIN1] = 0x7f;
371 0 : sc->shadow[dev][AK4524_DAC_GAIN0] = 0x7f;
372 0 : sc->shadow[dev][AK4524_DAC_GAIN1] = 0x7f;
373 : }
374 0 : }
375 :
376 : void
377 0 : delta_codec_write(struct envy_softc *sc, int dev, int addr, int data)
378 : {
379 : int bits, i, reg;
380 : int clk, dout, csmask, cs;
381 :
382 : /*
383 : * GPIO pin numbers
384 : */
385 0 : if (sc->card->subid == ENVY_SUBID_DELTA44) {
386 : clk = 0x20;
387 : dout = 0x10;
388 : csmask = 0xc0;
389 0 : cs = dev ? 0x40 : 0x80;
390 0 : } else {
391 : clk = 0x2;
392 : dout = 0x8;
393 : csmask = 0x70;
394 0 : cs = dev << 4;
395 : }
396 :
397 0 : reg = envy_gpio_getstate(sc);
398 0 : reg &= ~csmask;
399 0 : reg |= cs;
400 0 : envy_gpio_setstate(sc, reg);
401 0 : delay(1);
402 :
403 0 : bits = 0xa000 | (addr << 8) | data;
404 0 : for (i = 0; i < 16; i++) {
405 0 : reg &= ~(clk | dout);
406 0 : reg |= (bits & 0x8000) ? dout : 0;
407 0 : envy_gpio_setstate(sc, reg);
408 0 : delay(1);
409 :
410 0 : reg |= clk;
411 0 : envy_gpio_setstate(sc, reg);
412 0 : delay(1);
413 0 : bits <<= 1;
414 : }
415 :
416 0 : reg |= csmask;
417 0 : envy_gpio_setstate(sc, reg);
418 0 : delay(1);
419 0 : }
420 :
421 : /*
422 : * M-Audio Audiophile 192 specific code
423 : */
424 :
425 : /*
426 : * GPIO pin numbers
427 : */
428 : #define AP192K_GPIO_CLK 0x2
429 : #define AP192K_GPIO_DOUT 0x8
430 : #define AP192K_GPIO_CSMASK 0x30
431 : #define AP192K_GPIO_CS(dev) ((dev) << 4)
432 : #define AP192K_GPIO_ADC_PWR 0x800
433 : #define AP192K_GPIO_ADC_DFSMASK (3 << 9)
434 : #define AP192K_GPIO_ADC_DFS(v) ((v) << 9)
435 : #define AP192K_GPIO_MUTE 0x400000
436 :
437 : void
438 0 : ap192k_init(struct envy_softc *sc)
439 : {
440 : int i, reg;
441 :
442 : /* AK4358 */
443 0 : envy_codec_write(sc, 0, 0, 0); /* reset */
444 0 : delay(300);
445 0 : envy_codec_write(sc, 0, 0, 0x87); /* i2s mode */
446 0 : delay(1);
447 0 : for (i = 0; i < sc->card->noch; i++) {
448 0 : sc->shadow[0][AK4358_ATT(i)] = 0xff;
449 : }
450 :
451 : /* AK5385 */
452 0 : delay(1);
453 0 : reg = envy_gpio_getstate(sc);
454 0 : reg &= ~(AP192K_GPIO_ADC_PWR | AP192K_GPIO_ADC_DFSMASK);
455 : reg |= AP192K_GPIO_ADC_DFS(0);
456 0 : envy_gpio_setstate(sc, reg);
457 0 : reg |= AP192K_GPIO_ADC_PWR;
458 0 : envy_gpio_setstate(sc, reg);
459 0 : }
460 :
461 : void
462 0 : ap192k_codec_write(struct envy_softc *sc, int dev, int addr, int data)
463 : {
464 : int bits, i, reg;
465 :
466 0 : reg = envy_gpio_getstate(sc);
467 0 : reg &= ~AP192K_GPIO_CSMASK;
468 0 : reg |= AP192K_GPIO_CS(dev);
469 0 : envy_gpio_setstate(sc, reg);
470 0 : delay(1);
471 :
472 0 : bits = 0xa000 | (addr << 8) | data;
473 0 : for (i = 0; i < 16; i++) {
474 0 : reg &= ~(AP192K_GPIO_CLK | AP192K_GPIO_DOUT);
475 0 : reg |= (bits & 0x8000) ? AP192K_GPIO_DOUT : 0;
476 0 : envy_gpio_setstate(sc, reg);
477 0 : delay(1);
478 :
479 0 : reg |= AP192K_GPIO_CLK;
480 0 : envy_gpio_setstate(sc, reg);
481 0 : delay(1);
482 0 : bits <<= 1;
483 : }
484 :
485 0 : reg |= AP192K_GPIO_CSMASK;
486 0 : envy_gpio_setstate(sc, reg);
487 0 : delay(1);
488 0 : }
489 :
490 : /*
491 : * Terratec EWX specific code
492 : */
493 :
494 : /*
495 : * GPIO pin numbers
496 : */
497 : #define EWX_GPIO_CSMASK 0x01
498 : #define EWX_GPIO_DOUT 0x10
499 : #define EWX_GPIO_CLK 0x20
500 :
501 : void
502 0 : ewx_codec_write(struct envy_softc *sc, int dev, int addr, int data)
503 : {
504 : int bits, i, reg;
505 :
506 0 : reg = envy_gpio_getstate(sc);
507 0 : reg |= (EWX_GPIO_CSMASK | EWX_GPIO_CLK);
508 0 : envy_gpio_setstate(sc, reg);
509 0 : delay(1);
510 :
511 0 : bits = 0xa000 | (addr << 8) | data;
512 0 : for (i = 0; i < 16; i++) {
513 0 : reg &= ~(EWX_GPIO_CLK | EWX_GPIO_DOUT);
514 0 : reg |= (bits & 0x8000) ? EWX_GPIO_DOUT : 0;
515 0 : envy_gpio_setstate(sc, reg);
516 0 : delay(1);
517 :
518 0 : reg |= EWX_GPIO_CLK;
519 0 : envy_gpio_setstate(sc, reg);
520 0 : delay(1);
521 0 : bits <<= 1;
522 : }
523 :
524 0 : reg &= ~EWX_GPIO_CSMASK;
525 0 : envy_gpio_setstate(sc, reg);
526 0 : delay(1);
527 :
528 0 : reg |= EWX_GPIO_CSMASK;
529 0 : envy_gpio_setstate(sc, reg);
530 0 : delay(1);
531 0 : }
532 :
533 :
534 : /*
535 : * M-Audio Revolution 5.1 specific code
536 : */
537 :
538 : #define REVO51_GPIO_CLK 0x2
539 : #define REVO51_GPIO_DOUT 0x8
540 : #define REVO51_GPIO_CSMASK 0x30
541 : #define REVO51_GPIO_CS(dev) ((dev) ? 0x10 : 0x20)
542 : #define REVO51_MUTE 0x400000
543 : #define REVO51_PT2258S_SDA 0x40
544 : #define REVO51_PT2258S_SCL 0x80
545 : #define REVO51_PT2258S_ADDR 0x80
546 : #define REVO51_PT2258S_MUTE 6
547 :
548 : void
549 0 : revo51_init(struct envy_softc *sc)
550 : {
551 : int i, reg;
552 :
553 : /* AK4358 */
554 0 : envy_codec_write(sc, 0, 0, 0); /* reset */
555 0 : delay(300);
556 0 : envy_codec_write(sc, 0, 0, 0x87); /* i2s mode */
557 0 : for (i = 0; i < sc->card->noch; i++) {
558 0 : sc->shadow[0][AK4358_ATT(i)] = 0xff;
559 : }
560 :
561 : /* AK5365 */
562 0 : envy_codec_write(sc, 1, AK5365_RST, 0); /* reset */
563 0 : delay(300);
564 0 : envy_codec_write(sc, 1, AK5365_CTRL, AK5365_CTRL_I2S); /* i2s mode */
565 0 : envy_codec_write(sc, 1, AK5365_RST , AK5365_RST_NORM);
566 0 : sc->shadow[1][AK5365_ATT(0)] = 0x7f;
567 0 : sc->shadow[1][AK5365_ATT(1)] = 0x7f;
568 :
569 : /* PT2258S */
570 0 : envy_codec_write(sc, 2, REVO51_PT2258S_MUTE, 0xc0); /* reset */
571 0 : envy_codec_write(sc, 2, REVO51_PT2258S_MUTE, 0xf9); /* mute */
572 :
573 0 : reg = envy_gpio_getstate(sc);
574 0 : reg |= REVO51_MUTE;
575 0 : envy_gpio_setstate(sc, reg);
576 0 : }
577 :
578 : void
579 0 : revo51_codec_write(struct envy_softc *sc, int dev, int addr, int data)
580 : {
581 : int attn, bits, mask, reg;
582 0 : int xlat[6] = {0x90, 0x50, 0x10, 0x30, 0x70, 0xb0};
583 :
584 : /* AK4358 & AK5365 */
585 0 : if (dev < 2) {
586 0 : reg = envy_gpio_getstate(sc);
587 0 : reg &= ~REVO51_GPIO_CSMASK;
588 0 : reg |= REVO51_GPIO_CS(dev);
589 0 : envy_gpio_setstate(sc, reg);
590 0 : delay(1);
591 :
592 0 : bits = 0xa000 | (addr << 8) | data;
593 0 : for (mask = 0x8000; mask != 0; mask >>= 1) {
594 0 : reg &= ~(REVO51_GPIO_CLK | REVO51_GPIO_DOUT);
595 0 : reg |= (bits & mask) ? REVO51_GPIO_DOUT : 0;
596 0 : envy_gpio_setstate(sc, reg);
597 0 : delay(1);
598 :
599 0 : reg |= REVO51_GPIO_CLK;
600 0 : envy_gpio_setstate(sc, reg);
601 0 : delay(1);
602 : }
603 :
604 0 : reg |= REVO51_GPIO_CSMASK;
605 0 : envy_gpio_setstate(sc, reg);
606 0 : delay(1);
607 0 : return;
608 : }
609 :
610 : /* PT2258S */
611 0 : envy_gpio_i2c_start_bit(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL);
612 0 : envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL,
613 : REVO51_PT2258S_ADDR);
614 :
615 0 : if (addr == REVO51_PT2258S_MUTE) {
616 0 : envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
617 : REVO51_PT2258S_SCL, data);
618 0 : } else {
619 : /* 1's digit */
620 0 : attn = data % 10;
621 0 : attn += xlat[addr];
622 0 : envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
623 : REVO51_PT2258S_SCL, attn);
624 :
625 : /* 10's digit */
626 0 : attn = data / 10;
627 0 : attn += xlat[addr] - 0x10;
628 0 : envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
629 : REVO51_PT2258S_SCL, attn);
630 : }
631 :
632 0 : envy_gpio_i2c_stop_bit(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL);
633 0 : }
634 :
635 : /*
636 : * Generic AC'97 initialization
637 : */
638 :
639 : void
640 0 : envy_ac97_init(struct envy_softc *sc)
641 : {
642 0 : sc->isac97 = 1;
643 0 : sc->host_if.arg = sc;
644 0 : sc->host_if.attach = envy_ac97_attach_codec;
645 0 : sc->host_if.read = envy_ac97_read_codec;
646 0 : sc->host_if.write = envy_ac97_write_codec;
647 0 : sc->host_if.reset = envy_ac97_reset_codec;
648 0 : sc->host_if.flags = envy_ac97_flags_codec;
649 :
650 0 : if (ac97_attach(&sc->host_if) != 0)
651 0 : printf("%s: can't attach ac97\n", DEVNAME(sc));
652 0 : }
653 :
654 : /*
655 : * Dynex
656 : */
657 :
658 : void
659 0 : dynex_sc51_init(struct envy_softc *sc)
660 : {
661 0 : sc->codec_flags |= AC97_HOST_VT1616_DYNEX;
662 0 : envy_ac97_init(sc);
663 0 : }
664 :
665 : /*
666 : * ESI Julia specific code
667 : */
668 :
669 : void
670 0 : julia_init(struct envy_softc *sc)
671 : {
672 : int i;
673 :
674 0 : envy_codec_write(sc, 0, 0, 0); /* reset */
675 0 : delay(300);
676 0 : envy_codec_write(sc, 0, 0, 0x87); /* i2s mode */
677 0 : for (i = 0; i < sc->card->noch; i++) {
678 0 : sc->shadow[0][AK4358_ATT(i)] = 0xff;
679 : }
680 0 : }
681 :
682 : void
683 0 : julia_codec_write(struct envy_softc *sc, int dev, int addr, int data)
684 : {
685 : #define JULIA_AK4358_ADDR 0x11
686 0 : envy_i2c_write(sc, JULIA_AK4358_ADDR, addr, data);
687 0 : }
688 :
689 : /*
690 : * unknown card, ignore codecs setup and hope it works with the power on
691 : * settings
692 : */
693 :
694 : void
695 0 : unkenvy_init(struct envy_softc *sc)
696 : {
697 0 : }
698 :
699 : void
700 0 : unkenvy_codec_write(struct envy_softc *sc, int dev, int addr, int data)
701 : {
702 0 : }
703 :
704 : int
705 0 : unkenvy_codec_ndev(struct envy_softc *sc)
706 : {
707 0 : return 0;
708 : }
709 :
710 : /*
711 : * AK 4358 DAC specific code
712 : */
713 : int
714 0 : ak4358_dac_ndev(struct envy_softc *sc)
715 : {
716 : /* 1 volume knob per channel */
717 0 : return sc->card->noch;
718 : }
719 :
720 : void
721 0 : ak4358_dac_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
722 : {
723 0 : dev->type = AUDIO_MIXER_VALUE;
724 0 : dev->mixer_class = ENVY_MIX_CLASSOUT;
725 0 : dev->un.v.delta = 2;
726 0 : dev->un.v.num_channels = 1;
727 0 : snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
728 : AudioNline "-%d", idx);
729 0 : strlcpy(dev->un.v.units.name, AudioNvolume,
730 : MAX_AUDIO_DEV_LEN);
731 0 : }
732 :
733 : void
734 0 : ak4358_dac_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
735 : {
736 : int val;
737 :
738 0 : val = envy_codec_read(sc, 0, AK4358_ATT(idx)) & ~AK4358_ATT_EN;
739 0 : ctl->un.value.num_channels = 1;
740 0 : ctl->un.value.level[0] = 2 * val;
741 0 : }
742 :
743 : int
744 0 : ak4358_dac_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
745 : {
746 : int val;
747 :
748 0 : if (ctl->un.value.num_channels != 1)
749 0 : return EINVAL;
750 0 : val = ctl->un.value.level[0] / 2;
751 0 : envy_codec_write(sc, 0, AK4358_ATT(idx), val | AK4358_ATT_EN);
752 0 : return 0;
753 0 : }
754 :
755 : /*
756 : * AK 4524 DAC specific code
757 : */
758 : int
759 0 : ak4524_dac_ndev(struct envy_softc *sc)
760 : {
761 : /* 1 mute + 2 volume knobs per channel pair */
762 0 : return 3 * (sc->card->noch / 2);
763 : }
764 :
765 : void
766 0 : ak4524_dac_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
767 : {
768 : int ndev;
769 :
770 0 : ndev = sc->card->noch;
771 0 : if (idx < ndev) {
772 0 : dev->type = AUDIO_MIXER_VALUE;
773 0 : dev->mixer_class = ENVY_MIX_CLASSOUT;
774 0 : dev->un.v.delta = 2;
775 0 : dev->un.v.num_channels = 1;
776 0 : snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
777 : AudioNline "-%d", idx);
778 0 : strlcpy(dev->un.v.units.name, AudioNvolume,
779 : MAX_AUDIO_DEV_LEN);
780 0 : } else {
781 0 : idx -= ndev;
782 0 : dev->type = AUDIO_MIXER_ENUM;
783 0 : dev->mixer_class = ENVY_MIX_CLASSOUT;
784 0 : dev->un.e.member[0].ord = 0;
785 0 : strlcpy(dev->un.e.member[0].label.name, AudioNoff,
786 : MAX_AUDIO_DEV_LEN);
787 0 : dev->un.e.member[1].ord = 1;
788 0 : strlcpy(dev->un.e.member[1].label.name, AudioNon,
789 : MAX_AUDIO_DEV_LEN);
790 0 : dev->un.e.num_mem = 2;
791 0 : snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
792 0 : AudioNline "-%d:%d_" AudioNmute, 2 * idx, 2 * idx + 1);
793 : }
794 0 : }
795 :
796 : void
797 0 : ak4524_dac_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
798 : {
799 : int val, ndev;
800 :
801 0 : ndev = sc->card->noch;
802 0 : if (idx < ndev) {
803 0 : val = envy_codec_read(sc, idx / 2,
804 0 : (idx % 2) + AK4524_DAC_GAIN0);
805 0 : ctl->un.value.num_channels = 1;
806 0 : ctl->un.value.level[0] = 2 * val;
807 0 : } else {
808 0 : idx -= ndev;
809 0 : val = envy_codec_read(sc, idx, AK4524_DEEMVOL);
810 0 : ctl->un.ord = (val & AK4524_MUTE) ? 1 : 0;
811 : }
812 0 : }
813 :
814 : int
815 0 : ak4524_dac_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
816 : {
817 : int val, ndev;
818 :
819 0 : ndev = sc->card->noch;
820 0 : if (idx < ndev) {
821 0 : if (ctl->un.value.num_channels != 1)
822 0 : return EINVAL;
823 0 : val = ctl->un.value.level[0] / 2;
824 0 : envy_codec_write(sc, idx / 2,
825 0 : (idx % 2) + AK4524_DAC_GAIN0, val);
826 0 : } else {
827 0 : idx -= ndev;
828 0 : if (ctl->un.ord >= 2)
829 0 : return EINVAL;
830 0 : val = AK4524_DEEM_OFF | (ctl->un.ord ? AK4524_MUTE : 0);
831 0 : envy_codec_write(sc, idx, AK4524_DEEMVOL, val);
832 : }
833 0 : return 0;
834 0 : }
835 :
836 : /*
837 : * AK 4524 ADC specific code
838 : */
839 : int
840 0 : ak4524_adc_ndev(struct envy_softc *sc)
841 : {
842 : /* one volume per channel */
843 0 : return sc->card->nich;
844 : }
845 :
846 : void
847 0 : ak4524_adc_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
848 : {
849 0 : dev->type = AUDIO_MIXER_VALUE;
850 0 : dev->mixer_class = ENVY_MIX_CLASSIN;
851 0 : dev->un.v.delta = 2;
852 0 : dev->un.v.num_channels = 1;
853 0 : snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, AudioNline "-%d", idx);
854 0 : strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN);
855 0 : }
856 :
857 : void
858 0 : ak4524_adc_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
859 : {
860 : int val;
861 :
862 0 : val = envy_codec_read(sc, idx / 2, (idx % 2) + AK4524_ADC_GAIN0);
863 0 : ctl->un.value.num_channels = 1;
864 0 : ctl->un.value.level[0] = 2 * val;
865 0 : }
866 :
867 : int
868 0 : ak4524_adc_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
869 : {
870 : int val;
871 :
872 0 : if (ctl->un.value.num_channels != 1)
873 0 : return EINVAL;
874 0 : val = ctl->un.value.level[0] / 2;
875 0 : envy_codec_write(sc, idx / 2, (idx % 2) + AK4524_ADC_GAIN0, val);
876 0 : return 0;
877 0 : }
878 :
879 : /*
880 : * AK 5365 ADC specific code
881 : */
882 : int
883 0 : ak5365_adc_ndev(struct envy_softc *sc)
884 : {
885 : /* 1 source + 2 volume knobs per channel pair */
886 0 : return (sc->card->nich + 1);
887 : }
888 :
889 : void
890 0 : ak5365_adc_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
891 : {
892 : int ndev, i;
893 :
894 0 : ndev = sc->card->nich;
895 0 : if (idx < ndev) {
896 0 : dev->type = AUDIO_MIXER_VALUE;
897 0 : dev->mixer_class = ENVY_MIX_CLASSIN;
898 0 : dev->un.v.delta = 2;
899 0 : dev->un.v.num_channels = 1;
900 0 : snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
901 : AudioNline "-%d", idx);
902 0 : strlcpy(dev->un.v.units.name, AudioNvolume,
903 : MAX_AUDIO_DEV_LEN);
904 0 : } else {
905 0 : dev->type = AUDIO_MIXER_ENUM;
906 0 : dev->mixer_class = ENVY_MIX_CLASSIN;
907 0 : for (i = 0; i < 5; i++) {
908 0 : dev->un.e.member[i].ord = i;
909 0 : snprintf(dev->un.e.member[i].label.name,
910 : MAX_AUDIO_DEV_LEN, AudioNline "-%d", i);
911 : }
912 0 : dev->un.e.num_mem = 5;
913 0 : strlcpy(dev->label.name, AudioNsource,
914 : MAX_AUDIO_DEV_LEN);
915 : }
916 0 : }
917 :
918 : void
919 0 : ak5365_adc_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
920 : {
921 : int val, ndev;
922 :
923 0 : ndev = sc->card->nich;
924 0 : if (idx < ndev) {
925 0 : val = envy_codec_read(sc, 1, AK5365_ATT(idx));
926 0 : ctl->un.value.num_channels = 1;
927 0 : ctl->un.value.level[0] = 2 * val;
928 0 : } else {
929 0 : ctl->un.ord = envy_codec_read(sc, 1, AK5365_SRC);
930 : }
931 0 : }
932 :
933 : int
934 0 : ak5365_adc_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
935 : {
936 : int val, ndev;
937 :
938 0 : ndev = sc->card->nich;
939 0 : if (idx < ndev) {
940 0 : if (ctl->un.value.num_channels != 1)
941 0 : return EINVAL;
942 0 : val = ctl->un.value.level[0] / 2;
943 0 : envy_codec_write(sc, 1, AK5365_ATT(idx), val);
944 0 : } else {
945 0 : if (ctl->un.ord >= 5)
946 0 : return EINVAL;
947 0 : val = ctl->un.ord & AK5365_SRC_MASK;
948 0 : envy_codec_write(sc, 1, AK5365_SRC, val);
949 : }
950 0 : return 0;
951 0 : }
952 :
953 : /*
954 : * generic Envy24 and Envy24HT code, common to all cards
955 : */
956 :
957 : int
958 0 : envy_ccs_read(struct envy_softc *sc, int reg)
959 : {
960 : int val;
961 :
962 0 : val = bus_space_read_1(sc->ccs_iot, sc->ccs_ioh, reg);
963 0 : bus_space_barrier(sc->ccs_iot, sc->ccs_ioh, 0, sc->ccs_iosz,
964 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
965 0 : return val;
966 : }
967 :
968 : void
969 0 : envy_ccs_write(struct envy_softc *sc, int reg, int val)
970 : {
971 0 : bus_space_write_1(sc->ccs_iot, sc->ccs_ioh, reg, val);
972 0 : bus_space_barrier(sc->ccs_iot, sc->ccs_ioh, 0, sc->ccs_iosz,
973 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
974 0 : }
975 :
976 : int
977 0 : envy_mt_read_1(struct envy_softc *sc, int reg)
978 : {
979 : int val;
980 :
981 0 : val = bus_space_read_1(sc->mt_iot, sc->mt_ioh, reg);
982 0 : bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
983 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
984 0 : return val;
985 : }
986 :
987 : void
988 0 : envy_mt_write_1(struct envy_softc *sc, int reg, int val)
989 : {
990 0 : bus_space_write_1(sc->mt_iot, sc->mt_ioh, reg, val);
991 0 : bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
992 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
993 0 : }
994 :
995 : int
996 0 : envy_mt_read_2(struct envy_softc *sc, int reg)
997 : {
998 : int val;
999 :
1000 0 : val = bus_space_read_2(sc->mt_iot, sc->mt_ioh, reg);
1001 0 : bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
1002 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1003 0 : return val;
1004 : }
1005 :
1006 : void
1007 0 : envy_mt_write_2(struct envy_softc *sc, int reg, int val)
1008 : {
1009 0 : bus_space_write_2(sc->mt_iot, sc->mt_ioh, reg, val);
1010 0 : bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
1011 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1012 0 : }
1013 :
1014 : int
1015 0 : envy_mt_read_4(struct envy_softc *sc, int reg)
1016 : {
1017 : int val;
1018 :
1019 0 : val = bus_space_read_4(sc->mt_iot, sc->mt_ioh, reg);
1020 0 : bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
1021 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1022 0 : return val;
1023 : }
1024 :
1025 : void
1026 0 : envy_mt_write_4(struct envy_softc *sc, int reg, int val)
1027 : {
1028 0 : bus_space_write_4(sc->mt_iot, sc->mt_ioh, reg, val);
1029 0 : bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
1030 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1031 0 : }
1032 :
1033 : int
1034 0 : envy_cci_read(struct envy_softc *sc, int index)
1035 : {
1036 0 : envy_ccs_write(sc, ENVY_CCI_INDEX, index);
1037 0 : return (envy_ccs_read(sc, ENVY_CCI_DATA));
1038 : }
1039 :
1040 : void
1041 0 : envy_cci_write(struct envy_softc *sc, int index, int data)
1042 : {
1043 0 : envy_ccs_write(sc, ENVY_CCI_INDEX, index);
1044 0 : envy_ccs_write(sc, ENVY_CCI_DATA, data);
1045 0 : }
1046 :
1047 : int
1048 0 : envy_gpio_getstate(struct envy_softc *sc)
1049 : {
1050 0 : if (sc->isht) {
1051 0 : return envy_ccs_read(sc, ENVY_CCS_GPIODATA0) |
1052 0 : (envy_ccs_read(sc, ENVY_CCS_GPIODATA1) << 8) |
1053 0 : (envy_ccs_read(sc, ENVY_CCS_GPIODATA2) << 16);
1054 : } else
1055 0 : return envy_cci_read(sc, ENVY_CCI_GPIODATA);
1056 0 : }
1057 :
1058 : void
1059 0 : envy_gpio_setstate(struct envy_softc *sc, int reg)
1060 : {
1061 0 : if (sc->isht) {
1062 0 : envy_ccs_write(sc, ENVY_CCS_GPIODATA0, reg & 0xff);
1063 0 : envy_ccs_write(sc, ENVY_CCS_GPIODATA1, (reg >> 8) & 0xff);
1064 0 : envy_ccs_write(sc, ENVY_CCS_GPIODATA2, (reg >> 16) & 0xff);
1065 0 : } else
1066 0 : envy_cci_write(sc, ENVY_CCI_GPIODATA, reg);
1067 0 : }
1068 :
1069 : int
1070 0 : envy_gpio_getmask(struct envy_softc *sc)
1071 : {
1072 0 : if (sc->isht) {
1073 0 : return envy_ccs_read(sc, ENVY_CCS_GPIOMASK0) |
1074 0 : (envy_ccs_read(sc, ENVY_CCS_GPIOMASK1) << 8) |
1075 0 : (envy_ccs_read(sc, ENVY_CCS_GPIOMASK2) << 16);
1076 : } else
1077 0 : return envy_cci_read(sc, ENVY_CCI_GPIOMASK);
1078 0 : }
1079 :
1080 : void
1081 0 : envy_gpio_setmask(struct envy_softc *sc, int mask)
1082 : {
1083 0 : if (sc->isht) {
1084 0 : envy_ccs_write(sc, ENVY_CCS_GPIOMASK0, mask & 0xff);
1085 0 : envy_ccs_write(sc, ENVY_CCS_GPIOMASK1, (mask >> 8) & 0xff);
1086 0 : envy_ccs_write(sc, ENVY_CCS_GPIOMASK2, (mask >> 16) & 0xff);
1087 0 : } else
1088 0 : envy_cci_write(sc, ENVY_CCI_GPIOMASK, mask);
1089 0 : }
1090 :
1091 : int
1092 0 : envy_gpio_getdir(struct envy_softc *sc)
1093 : {
1094 0 : if (sc->isht) {
1095 0 : return envy_ccs_read(sc, ENVY_CCS_GPIODIR0) |
1096 0 : (envy_ccs_read(sc, ENVY_CCS_GPIODIR1) << 8) |
1097 0 : (envy_ccs_read(sc, ENVY_CCS_GPIODIR2) << 16);
1098 : } else
1099 0 : return envy_cci_read(sc, ENVY_CCI_GPIODIR);
1100 0 : }
1101 :
1102 : void
1103 0 : envy_gpio_setdir(struct envy_softc *sc, int dir)
1104 : {
1105 0 : if (sc->isht) {
1106 0 : envy_ccs_write(sc, ENVY_CCS_GPIODIR0, dir & 0xff);
1107 0 : envy_ccs_write(sc, ENVY_CCS_GPIODIR1, (dir >> 8) & 0xff);
1108 0 : envy_ccs_write(sc, ENVY_CCS_GPIODIR2, (dir >> 16) & 0xff);
1109 0 : } else
1110 0 : envy_cci_write(sc, ENVY_CCI_GPIODIR, dir);
1111 0 : }
1112 :
1113 : void
1114 0 : envy_gpio_i2c_start_bit(struct envy_softc *sc, int sda, int scl)
1115 : {
1116 : int reg;
1117 :
1118 0 : reg = envy_gpio_getstate(sc);
1119 0 : reg |= (sda | scl);
1120 0 : envy_gpio_setstate(sc, reg);
1121 0 : delay(5);
1122 0 : reg &= ~sda;
1123 0 : envy_gpio_setstate(sc, reg);
1124 0 : delay(4);
1125 0 : reg &= ~scl;
1126 0 : envy_gpio_setstate(sc, reg);
1127 0 : delay(5);
1128 0 : }
1129 :
1130 : void
1131 0 : envy_gpio_i2c_stop_bit(struct envy_softc *sc, int sda, int scl)
1132 : {
1133 : int reg;
1134 :
1135 0 : reg = envy_gpio_getstate(sc);
1136 0 : reg &= ~sda;
1137 0 : reg |= scl;
1138 0 : envy_gpio_setstate(sc, reg);
1139 0 : delay(4);
1140 0 : reg |= sda;
1141 0 : envy_gpio_setstate(sc, reg);
1142 0 : }
1143 :
1144 : void
1145 0 : envy_gpio_i2c_byte_out(struct envy_softc *sc, int sda, int scl, int val)
1146 : {
1147 : int mask, reg;
1148 :
1149 0 : reg = envy_gpio_getstate(sc);
1150 :
1151 0 : for (mask = 0x80; mask != 0; mask >>= 1) {
1152 0 : reg &= ~sda;
1153 0 : reg |= (val & mask) ? sda : 0;
1154 0 : envy_gpio_setstate(sc, reg);
1155 0 : delay(1);
1156 0 : reg |= scl;
1157 0 : envy_gpio_setstate(sc, reg);
1158 0 : delay(4);
1159 0 : reg &= ~scl;
1160 0 : envy_gpio_setstate(sc, reg);
1161 0 : delay(5);
1162 : }
1163 :
1164 0 : reg |= scl;
1165 0 : envy_gpio_setstate(sc, reg);
1166 0 : delay(4);
1167 0 : reg &= ~scl;
1168 0 : envy_gpio_setstate(sc, reg);
1169 0 : delay(5);
1170 0 : }
1171 :
1172 : void
1173 0 : envy_i2c_wait(struct envy_softc *sc)
1174 : {
1175 : int timeout = 50, st;
1176 :
1177 0 : for (;;) {
1178 0 : st = envy_ccs_read(sc, ENVY_I2C_CTL);
1179 0 : if (!(st & ENVY_I2C_CTL_BUSY))
1180 : break;
1181 0 : if (timeout == 0) {
1182 0 : printf("%s: i2c busy timeout\n", DEVNAME(sc));
1183 0 : break;
1184 : }
1185 0 : delay(50);
1186 0 : timeout--;
1187 : }
1188 0 : }
1189 :
1190 : int
1191 0 : envy_i2c_read(struct envy_softc *sc, int dev, int addr)
1192 : {
1193 0 : envy_i2c_wait(sc);
1194 0 : envy_ccs_write(sc, ENVY_I2C_ADDR, addr);
1195 0 : envy_i2c_wait(sc);
1196 0 : envy_ccs_write(sc, ENVY_I2C_DEV, dev << 1);
1197 0 : envy_i2c_wait(sc);
1198 0 : return envy_ccs_read(sc, ENVY_I2C_DATA);
1199 : }
1200 :
1201 : void
1202 0 : envy_i2c_write(struct envy_softc *sc, int dev, int addr, int data)
1203 : {
1204 0 : if (dev == 0x50) {
1205 0 : printf("%s: writing on eeprom is evil...\n", DEVNAME(sc));
1206 0 : return;
1207 : }
1208 0 : envy_i2c_wait(sc);
1209 0 : envy_ccs_write(sc, ENVY_I2C_ADDR, addr);
1210 0 : envy_i2c_wait(sc);
1211 0 : envy_ccs_write(sc, ENVY_I2C_DATA, data);
1212 0 : envy_i2c_wait(sc);
1213 0 : envy_ccs_write(sc, ENVY_I2C_DEV, (dev << 1) | 1);
1214 0 : }
1215 :
1216 : int
1217 0 : envy_codec_read(struct envy_softc *sc, int dev, int addr) {
1218 0 : return sc->shadow[dev][addr];
1219 : }
1220 :
1221 : void
1222 0 : envy_codec_write(struct envy_softc *sc, int dev, int addr, int data)
1223 : {
1224 : DPRINTFN(2, "envy_codec_write: %d, %d, 0x%x\n", dev, addr, data);
1225 0 : sc->shadow[dev][addr] = data;
1226 0 : sc->card->codec_write(sc, dev, addr, data);
1227 0 : }
1228 :
1229 : int
1230 0 : envy_eeprom_gpioxxx(struct envy_softc *sc, int addr)
1231 : {
1232 : int val;
1233 :
1234 0 : val = sc->eeprom[addr];
1235 0 : if (sc->isht) {
1236 0 : val |= sc->eeprom[++addr] << 8;
1237 0 : val |= sc->eeprom[++addr] << 16;
1238 0 : }
1239 0 : return val;
1240 : }
1241 :
1242 : int
1243 0 : envy_ac97_wait(struct envy_softc *sc)
1244 : {
1245 : int timeout = 50, st;
1246 :
1247 0 : for (;;) {
1248 0 : st = envy_mt_read_1(sc, ENVY_MT_AC97_CMD);
1249 0 : if ((st & ENVY_MT_AC97_READY) && !(st & ENVY_MT_AC97_CMD_MASK)) {
1250 : st = 0;
1251 0 : break;
1252 : }
1253 0 : if (timeout == 0) {
1254 : st = -1;
1255 0 : break;
1256 : }
1257 0 : delay(50);
1258 0 : timeout--;
1259 : }
1260 :
1261 0 : return (st);
1262 : }
1263 :
1264 : int
1265 0 : envy_ac97_attach_codec(void *hdl, struct ac97_codec_if *codec_if)
1266 : {
1267 0 : struct envy_softc *sc = hdl;
1268 :
1269 0 : sc->codec_if = codec_if;
1270 :
1271 0 : return (0);
1272 : }
1273 :
1274 : int
1275 0 : envy_ac97_read_codec(void *hdl, u_int8_t reg, u_int16_t *result)
1276 : {
1277 0 : struct envy_softc *sc = hdl;
1278 :
1279 0 : if (envy_ac97_wait(sc)) {
1280 0 : printf("%s: envy_ac97_read_codec: timed out\n", DEVNAME(sc));
1281 0 : return (-1);
1282 : }
1283 :
1284 0 : envy_mt_write_1(sc, ENVY_MT_AC97_IDX, reg & 0x7f);
1285 0 : envy_mt_write_1(sc, ENVY_MT_AC97_CMD,
1286 : ENVY_MT_AC97_CMD_RD);
1287 0 : delay(50);
1288 :
1289 0 : if (envy_ac97_wait(sc)) {
1290 0 : printf("%s: envy_ac97_read_codec: timed out\n", DEVNAME(sc));
1291 0 : return (-1);
1292 : }
1293 :
1294 0 : *result = envy_mt_read_2(sc, ENVY_MT_AC97_DATA);
1295 :
1296 0 : return (0);
1297 0 : }
1298 :
1299 : int
1300 0 : envy_ac97_write_codec(void *hdl, u_int8_t reg, u_int16_t data)
1301 : {
1302 0 : struct envy_softc *sc = hdl;
1303 :
1304 0 : if (envy_ac97_wait(sc)) {
1305 0 : printf("%s: envy_ac97_write_codec: timed out\n", DEVNAME(sc));
1306 0 : return (-1);
1307 : }
1308 :
1309 0 : envy_mt_write_1(sc, ENVY_MT_AC97_IDX, reg & 0x7f);
1310 0 : envy_mt_write_2(sc, ENVY_MT_AC97_DATA, data);
1311 0 : envy_mt_write_1(sc, ENVY_MT_AC97_CMD,
1312 : ENVY_MT_AC97_CMD_WR);
1313 0 : delay(50);
1314 :
1315 0 : return (0);
1316 0 : }
1317 :
1318 : void
1319 0 : envy_ac97_reset_codec(void *hdl)
1320 : {
1321 0 : struct envy_softc *sc = hdl;
1322 :
1323 0 : envy_mt_write_1(sc, ENVY_MT_AC97_CMD, ENVY_MT_AC97_CMD_RST);
1324 0 : delay(50);
1325 0 : envy_mt_write_1(sc, ENVY_MT_AC97_CMD, 0);
1326 0 : delay(50);
1327 :
1328 0 : if (envy_ac97_wait(sc)) {
1329 0 : printf("%s: envy_ac97_reset_codec: timed out\n", DEVNAME(sc));
1330 0 : }
1331 :
1332 : return;
1333 0 : }
1334 :
1335 : enum ac97_host_flags
1336 0 : envy_ac97_flags_codec(void *hdl)
1337 : {
1338 0 : struct envy_softc *sc = hdl;
1339 :
1340 0 : return (sc->codec_flags);
1341 : }
1342 :
1343 : void
1344 0 : envy_midi_wait(struct envy_softc *sc)
1345 : {
1346 : int i, st;
1347 :
1348 0 : for (i = 100;; i--) {
1349 0 : st = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
1350 0 : if (!(st & ENVY_MIDISTAT_OBUSY(sc)))
1351 : break;
1352 0 : if (i == 0) {
1353 0 : printf("%s: midi wait timeout\n", DEVNAME(sc));
1354 0 : break;
1355 : }
1356 0 : delay(10);
1357 : }
1358 0 : }
1359 :
1360 : void
1361 0 : envy_reset(struct envy_softc *sc)
1362 : {
1363 : int i, reg;
1364 :
1365 : /*
1366 : * full reset
1367 : */
1368 0 : envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_RESET | ENVY_CTL_NATIVE);
1369 0 : delay(200);
1370 0 : envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_NATIVE);
1371 0 : delay(200);
1372 :
1373 : /*
1374 : * read EEPROM using i2c device or from a static array
1375 : */
1376 0 : if (sc->card->eeprom == NULL) {
1377 0 : for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) {
1378 0 : sc->eeprom[i] = envy_i2c_read(sc, ENVY_I2C_DEV_EEPROM, i);
1379 : }
1380 : #ifdef ENVY_DEBUG
1381 : printf("%s: eeprom: ", DEVNAME(sc));
1382 : for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) {
1383 : printf(" %02x", (unsigned)sc->eeprom[i]);
1384 : }
1385 : printf("\n");
1386 : #endif
1387 : } else
1388 0 : memcpy(sc->eeprom, sc->card->eeprom, ENVY_EEPROM_MAXSZ);
1389 :
1390 : /*
1391 : * write EEPROM values to corresponding registers
1392 : */
1393 0 : if (sc->isht) {
1394 0 : envy_ccs_write(sc, ENVY_CCS_CONF,
1395 0 : sc->eeprom[ENVY_EEPROM_CONF]);
1396 0 : envy_ccs_write(sc, ENVY_CCS_ACLINK,
1397 0 : sc->eeprom[ENVY_EEPROM_ACLINK]);
1398 0 : envy_ccs_write(sc, ENVY_CCS_I2S,
1399 0 : sc->eeprom[ENVY_EEPROM_I2S]);
1400 0 : envy_ccs_write(sc, ENVY_CCS_SPDIF,
1401 0 : sc->eeprom[ENVY_EEPROM_SPDIF]);
1402 0 : } else {
1403 0 : pci_conf_write(sc->pci_pc, sc->pci_tag, ENVY_CONF,
1404 0 : sc->eeprom[ENVY_EEPROM_CONF] |
1405 0 : (sc->eeprom[ENVY_EEPROM_ACLINK] << 8) |
1406 0 : (sc->eeprom[ENVY_EEPROM_I2S] << 16) |
1407 0 : (sc->eeprom[ENVY_EEPROM_SPDIF] << 24));
1408 : }
1409 :
1410 0 : envy_gpio_setmask(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIOMASK(sc)));
1411 0 : envy_gpio_setdir(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIODIR(sc)));
1412 0 : envy_gpio_setstate(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIOST(sc)));
1413 :
1414 : DPRINTF("%s: gpio_mask = %02x\n", DEVNAME(sc),
1415 : envy_gpio_getmask(sc));
1416 : DPRINTF("%s: gpio_dir = %02x\n", DEVNAME(sc),
1417 : envy_gpio_getdir(sc));
1418 : DPRINTF("%s: gpio_state = %02x\n", DEVNAME(sc),
1419 : envy_gpio_getstate(sc));
1420 :
1421 0 : if (sc->isht) {
1422 : /*
1423 : * set water marks so we get an interrupt for each byte
1424 : */
1425 0 : envy_ccs_write(sc, ENVY_CCS_MIDIWAT, 1);
1426 0 : envy_ccs_write(sc, ENVY_CCS_MIDIWAT, 1 | ENVY_CCS_MIDIWAT_RX);
1427 0 : }
1428 :
1429 : /*
1430 : * switch to UART mode
1431 : */
1432 0 : envy_ccs_write(sc, ENVY_CCS_MIDISTAT0, 0xff);
1433 0 : envy_midi_wait(sc);
1434 0 : envy_ccs_write(sc, ENVY_CCS_MIDISTAT0, ENVY_MIDISTAT_UART);
1435 0 : envy_midi_wait(sc);
1436 0 : if (!sc->isht)
1437 0 : (void)envy_ccs_read(sc, ENVY_CCS_MIDIDATA0);
1438 :
1439 : /*
1440 : * clear all interrupts and unmask used ones
1441 : */
1442 0 : envy_ccs_write(sc, ENVY_CCS_INTSTAT, 0xff);
1443 : reg = ~ENVY_CCS_INT_MT;
1444 0 : if (sc->midi_isopen)
1445 0 : reg &= ~ENVY_CCS_INT_MIDI0;
1446 0 : envy_ccs_write(sc, ENVY_CCS_INTMASK, ~ENVY_CCS_INT_MT);
1447 0 : if (sc->isht) {
1448 0 : envy_mt_write_1(sc, ENVY_MT_NSTREAM, 4 - sc->card->noch / 2);
1449 0 : envy_mt_write_1(sc, ENVY_MT_IMASK, ~(ENVY_MT_IMASK_PDMA0 |
1450 : ENVY_MT_IMASK_RDMA0 | ENVY_MT_IMASK_ERR));
1451 0 : }
1452 0 : sc->iactive = 0;
1453 0 : sc->oactive = 0;
1454 0 : sc->card->init(sc);
1455 0 : }
1456 :
1457 : int
1458 0 : envy_lineout_getsrc(struct envy_softc *sc, int out)
1459 : {
1460 : int reg, shift, src;
1461 :
1462 0 : if (sc->isht) {
1463 0 : reg = envy_mt_read_4(sc, ENVY_MT_HTSRC);
1464 : DPRINTF("%s: outsrc=%x\n", DEVNAME(sc), reg);
1465 0 : shift = 3 * (out / 2) + ((out & 1) ? 20 : 8);
1466 0 : src = (reg >> shift) & ENVY_MT_HTSRC_MASK;
1467 0 : if (src == ENVY_MT_HTSRC_DMA) {
1468 0 : return ENVY_MIX_OUTSRC_DMA;
1469 : } else {
1470 0 : src -= ENVY_MT_HTSRC_LINE;
1471 0 : return ENVY_MIX_OUTSRC_LINEIN + src;
1472 : }
1473 : }
1474 :
1475 0 : reg = envy_mt_read_2(sc, ENVY_MT_OUTSRC);
1476 : DPRINTF("%s: outsrc=%x\n", DEVNAME(sc), reg);
1477 0 : shift = (out & 1) ? (out & ~1) + 8 : out;
1478 0 : src = (reg >> shift) & 3;
1479 0 : if (src == ENVY_MT_OUTSRC_DMA) {
1480 0 : return ENVY_MIX_OUTSRC_DMA;
1481 0 : } else if (src == ENVY_MT_OUTSRC_MON) {
1482 0 : return ENVY_MIX_OUTSRC_MON;
1483 : }
1484 0 : reg = envy_mt_read_4(sc, ENVY_MT_INSEL);
1485 : DPRINTF("%s: insel=%x\n", DEVNAME(sc), reg);
1486 0 : reg = (reg >> (out * 4)) & 0xf;
1487 0 : if (src == ENVY_MT_OUTSRC_LINE)
1488 0 : return ENVY_MIX_OUTSRC_LINEIN + (reg & 7);
1489 : else
1490 0 : return ENVY_MIX_OUTSRC_SPDIN + (reg >> 3);
1491 0 : }
1492 :
1493 : void
1494 0 : envy_lineout_setsrc(struct envy_softc *sc, int out, int src)
1495 : {
1496 : int reg, shift, mask, sel;
1497 :
1498 0 : if (sc->isht) {
1499 0 : if (src < ENVY_MIX_OUTSRC_SPDIN) {
1500 : sel = ENVY_MT_HTSRC_LINE;
1501 0 : sel += src;
1502 0 : } else if (src < ENVY_MIX_OUTSRC_DMA) {
1503 : sel = ENVY_MT_HTSRC_SPD;
1504 0 : sel += src - ENVY_MIX_OUTSRC_SPDIN;
1505 0 : } else {
1506 : sel = ENVY_MT_HTSRC_DMA;
1507 : }
1508 0 : shift = 3 * (out / 2) + ((out & 1) ? 20 : 8);
1509 0 : mask = ENVY_MT_HTSRC_MASK << shift;
1510 0 : reg = envy_mt_read_4(sc, ENVY_MT_HTSRC);
1511 0 : reg = (reg & ~mask) | (sel << shift);
1512 0 : envy_mt_write_4(sc, ENVY_MT_HTSRC, reg);
1513 : DPRINTF("%s: outsrc <- %x\n", DEVNAME(sc), reg);
1514 0 : return;
1515 : }
1516 :
1517 0 : if (src < ENVY_MIX_OUTSRC_DMA) {
1518 : /*
1519 : * linein and spdin are used as output source so we
1520 : * must select the input source channel number
1521 : */
1522 0 : if (src < ENVY_MIX_OUTSRC_SPDIN)
1523 0 : sel = src - ENVY_MIX_OUTSRC_LINEIN;
1524 : else
1525 0 : sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3;
1526 :
1527 0 : shift = out * ENVY_MT_INSEL_BITS;
1528 0 : mask = ENVY_MT_INSEL_MASK << shift;
1529 0 : reg = envy_mt_read_4(sc, ENVY_MT_INSEL);
1530 0 : reg = (reg & ~mask) | (sel << shift);
1531 0 : envy_mt_write_4(sc, ENVY_MT_INSEL, reg);
1532 : DPRINTF("%s: insel <- %x\n", DEVNAME(sc), reg);
1533 0 : }
1534 :
1535 : /*
1536 : * set the lineout route register
1537 : */
1538 0 : if (src < ENVY_MIX_OUTSRC_SPDIN) {
1539 : sel = ENVY_MT_OUTSRC_LINE;
1540 0 : } else if (src < ENVY_MIX_OUTSRC_DMA) {
1541 : sel = ENVY_MT_OUTSRC_SPD;
1542 0 : } else if (src == ENVY_MIX_OUTSRC_DMA) {
1543 : sel = ENVY_MT_OUTSRC_DMA;
1544 0 : } else {
1545 : sel = ENVY_MT_OUTSRC_MON;
1546 : }
1547 0 : shift = (out & 1) ? (out & ~1) + 8 : out;
1548 0 : mask = ENVY_MT_OUTSRC_MASK << shift;
1549 0 : reg = envy_mt_read_2(sc, ENVY_MT_OUTSRC);
1550 0 : reg = (reg & ~mask) | (sel << shift);
1551 0 : envy_mt_write_2(sc, ENVY_MT_OUTSRC, reg);
1552 : DPRINTF("%s: outsrc <- %x\n", DEVNAME(sc), reg);
1553 0 : }
1554 :
1555 :
1556 : int
1557 0 : envy_spdout_getsrc(struct envy_softc *sc, int out)
1558 : {
1559 : int reg, src, sel;
1560 :
1561 0 : reg = envy_mt_read_2(sc, ENVY_MT_SPDROUTE);
1562 : DPRINTF("%s: spdroute=%x\n", DEVNAME(sc), reg);
1563 0 : src = (out == 0) ? reg : reg >> 2;
1564 0 : src &= ENVY_MT_SPDSRC_MASK;
1565 0 : if (src == ENVY_MT_SPDSRC_DMA) {
1566 0 : return ENVY_MIX_OUTSRC_DMA;
1567 0 : } else if (src == ENVY_MT_SPDSRC_MON) {
1568 0 : return ENVY_MIX_OUTSRC_MON;
1569 : }
1570 :
1571 0 : sel = (out == 0) ? reg >> 8 : reg >> 12;
1572 0 : sel &= ENVY_MT_SPDSEL_MASK;
1573 0 : if (src == ENVY_MT_SPDSRC_LINE)
1574 0 : return ENVY_MIX_OUTSRC_LINEIN + (sel & 7);
1575 : else
1576 0 : return ENVY_MIX_OUTSRC_SPDIN + (sel >> 3);
1577 0 : }
1578 :
1579 : void
1580 0 : envy_spdout_setsrc(struct envy_softc *sc, int out, int src)
1581 : {
1582 : int reg, shift, mask, sel;
1583 :
1584 0 : reg = envy_mt_read_2(sc, ENVY_MT_SPDROUTE);
1585 0 : if (src < ENVY_MIX_OUTSRC_DMA) {
1586 : /*
1587 : * linein and spdin are used as output source so we
1588 : * must select the input source channel number
1589 : */
1590 0 : if (src < ENVY_MIX_OUTSRC_SPDIN)
1591 0 : sel = src - ENVY_MIX_OUTSRC_LINEIN;
1592 : else
1593 0 : sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3;
1594 :
1595 0 : shift = 8 + out * ENVY_MT_SPDSEL_BITS;
1596 0 : mask = ENVY_MT_SPDSEL_MASK << shift;
1597 0 : reg = (reg & ~mask) | (sel << shift);
1598 0 : }
1599 :
1600 : /*
1601 : * set the lineout route register
1602 : */
1603 0 : if (src < ENVY_MIX_OUTSRC_SPDIN) {
1604 : sel = ENVY_MT_OUTSRC_LINE;
1605 0 : } else if (src < ENVY_MIX_OUTSRC_DMA) {
1606 : sel = ENVY_MT_OUTSRC_SPD;
1607 0 : } else if (src == ENVY_MIX_OUTSRC_DMA) {
1608 : sel = ENVY_MT_OUTSRC_DMA;
1609 0 : } else {
1610 : sel = ENVY_MT_OUTSRC_MON;
1611 : }
1612 0 : shift = out * 2;
1613 0 : mask = ENVY_MT_SPDSRC_MASK << shift;
1614 0 : reg = (reg & ~mask) | (sel << shift);
1615 0 : envy_mt_write_2(sc, ENVY_MT_SPDROUTE, reg);
1616 : DPRINTF("%s: spdroute <- %x\n", DEVNAME(sc), reg);
1617 0 : }
1618 :
1619 : void
1620 0 : envy_mon_getvol(struct envy_softc *sc, int idx, int ch, int *val)
1621 : {
1622 : int reg;
1623 :
1624 0 : envy_mt_write_2(sc, ENVY_MT_MONIDX, idx);
1625 0 : reg = envy_mt_read_1(sc, ENVY_MT_MONDATA + ch);
1626 0 : *val = 0x7f - (reg & 0x7f);
1627 0 : }
1628 :
1629 : void
1630 0 : envy_mon_setvol(struct envy_softc *sc, int idx, int ch, int val)
1631 : {
1632 : int reg;
1633 :
1634 0 : envy_mt_write_2(sc, ENVY_MT_MONIDX, idx);
1635 0 : reg = 0x7f - val;
1636 : DPRINTF("%s: mon=%d/%d <- %d\n", DEVNAME(sc), reg, ch, val);
1637 0 : envy_mt_write_1(sc, ENVY_MT_MONDATA + ch, reg);
1638 0 : }
1639 :
1640 : int
1641 0 : envymatch(struct device *parent, void *match, void *aux)
1642 : {
1643 0 : return pci_matchbyid((struct pci_attach_args *)aux, envy_matchids,
1644 : sizeof(envy_matchids) / sizeof(envy_matchids[0]));
1645 : }
1646 :
1647 : void
1648 0 : envyattach(struct device *parent, struct device *self, void *aux)
1649 : {
1650 0 : struct envy_softc *sc = (struct envy_softc *)self;
1651 0 : struct pci_attach_args *pa = (struct pci_attach_args *)aux;
1652 0 : pci_intr_handle_t ih;
1653 : const char *intrstr;
1654 : int subid;
1655 :
1656 : #if NMIDI > 0
1657 0 : sc->midi_isopen = 0;
1658 : #endif
1659 0 : sc->pci_tag = pa->pa_tag;
1660 0 : sc->pci_pc = pa->pa_pc;
1661 0 : sc->pci_dmat = pa->pa_dmat;
1662 0 : sc->pci_ih = NULL;
1663 0 : sc->ibuf.addr = sc->obuf.addr = NULL;
1664 0 : sc->ccs_iosz = 0;
1665 0 : sc->mt_iosz = 0;
1666 0 : sc->isht = (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ICENSEMBLE_VT172x);
1667 :
1668 0 : if (pci_mapreg_map(pa, ENVY_CTL_BAR, PCI_MAPREG_TYPE_IO, 0,
1669 0 : &sc->ccs_iot, &sc->ccs_ioh, NULL, &sc->ccs_iosz, 0)) {
1670 0 : printf(": can't map ctl i/o space\n");
1671 0 : sc->ccs_iosz = 0;
1672 0 : return;
1673 : }
1674 0 : if (pci_mapreg_map(pa, ENVY_MT_BAR(sc->isht), PCI_MAPREG_TYPE_IO, 0,
1675 0 : &sc->mt_iot, &sc->mt_ioh, NULL, &sc->mt_iosz, 0)) {
1676 0 : printf(": can't map mt i/o space\n");
1677 0 : sc->mt_iosz = 0;
1678 0 : return;
1679 : }
1680 0 : if (pci_intr_map(pa, &ih)) {
1681 0 : printf(": can't map interrupt\n");
1682 0 : }
1683 0 : intrstr = pci_intr_string(sc->pci_pc, ih);
1684 0 : sc->pci_ih = pci_intr_establish(sc->pci_pc, ih, IPL_AUDIO | IPL_MPSAFE,
1685 0 : envy_intr, sc, sc->dev.dv_xname);
1686 0 : if (sc->pci_ih == NULL) {
1687 0 : printf(": can't establish interrupt");
1688 0 : if (intrstr)
1689 0 : printf(" at %s", intrstr);
1690 0 : printf("\n");
1691 0 : return;
1692 : }
1693 0 : printf(": %s\n", intrstr);
1694 0 : subid = pci_conf_read(sc->pci_pc, sc->pci_tag, PCI_SUBVEND_0);
1695 0 : sc->card = sc->isht ? envy_cards_ht : envy_cards;
1696 0 : while (sc->card->subid != subid) {
1697 0 : if (sc->card->subid == 0)
1698 : break;
1699 0 : sc->card++;
1700 : }
1701 0 : printf("%s: %s, %u inputs, %u outputs\n", DEVNAME(sc),
1702 0 : sc->card->name, sc->card->nich, sc->card->noch);
1703 0 : envy_reset(sc);
1704 0 : sc->audio = audio_attach_mi(&envy_hw_if, sc, &sc->dev);
1705 : #if NMIDI > 0
1706 0 : if (sc->card->nmidi > 0 && (!sc->isht ||
1707 0 : sc->eeprom[ENVY_EEPROM_CONF] & ENVY_CONF_MIDI)) {
1708 0 : sc->midi = midi_attach_mi(&envy_midi_hw_if, sc, &sc->dev);
1709 0 : }
1710 : #endif
1711 0 : }
1712 :
1713 : int
1714 0 : envydetach(struct device *self, int flags)
1715 : {
1716 0 : struct envy_softc *sc = (struct envy_softc *)self;
1717 :
1718 0 : if (sc->pci_ih != NULL) {
1719 0 : pci_intr_disestablish(sc->pci_pc, sc->pci_ih);
1720 0 : sc->pci_ih = NULL;
1721 0 : }
1722 0 : if (sc->ccs_iosz) {
1723 0 : bus_space_unmap(sc->ccs_iot, sc->ccs_ioh, sc->ccs_iosz);
1724 0 : }
1725 0 : if (sc->mt_iosz) {
1726 0 : bus_space_unmap(sc->mt_iot, sc->mt_ioh, sc->mt_iosz);
1727 0 : }
1728 0 : return 0;
1729 : }
1730 :
1731 : int
1732 0 : envyactivate(struct device *self, int act)
1733 : {
1734 0 : struct envy_softc *sc = (struct envy_softc *)self;
1735 :
1736 0 : if (act == DVACT_RESUME) {
1737 : /*
1738 : * The audio(4) layer will restore parameters and, if
1739 : * needed, start DMA. So we only need to reach the
1740 : * same device state as after the audio_attach() call.
1741 : */
1742 0 : envy_reset(sc);
1743 0 : }
1744 0 : return config_activate_children(self, act);
1745 : }
1746 :
1747 : int
1748 0 : envy_open(void *self, int flags)
1749 : {
1750 0 : return 0;
1751 : }
1752 :
1753 : void
1754 0 : envy_close(void *self)
1755 : {
1756 0 : }
1757 :
1758 : void *
1759 0 : envy_allocm(void *self, int dir, size_t size, int type, int flags)
1760 : {
1761 0 : struct envy_softc *sc = (struct envy_softc *)self;
1762 : int err, wait;
1763 : struct envy_buf *buf;
1764 : bus_addr_t dma_addr;
1765 :
1766 0 : buf = (dir == AUMODE_RECORD) ? &sc->ibuf : &sc->obuf;
1767 0 : if (buf->addr != NULL) {
1768 : DPRINTF("%s: multiple alloc, dir = %d\n", DEVNAME(sc), dir);
1769 0 : return NULL;
1770 : }
1771 0 : buf->size = size;
1772 0 : wait = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
1773 :
1774 : #define ENVY_ALIGN 4
1775 : #define ENVY_MAXADDR ((1 << 28) - 1)
1776 :
1777 0 : buf->addr = (caddr_t)uvm_km_kmemalloc_pla(kernel_map,
1778 0 : uvm.kernel_object, buf->size, 0, UVM_KMF_NOWAIT, 0,
1779 : (paddr_t)ENVY_MAXADDR, 0, 0, 1);
1780 0 : if (buf->addr == NULL) {
1781 : DPRINTF("%s: unable to alloc dma segment\n", DEVNAME(sc));
1782 : goto err_ret;
1783 : }
1784 0 : err = bus_dmamap_create(sc->pci_dmat, buf->size, 1, buf->size, 0,
1785 : wait, &buf->map);
1786 0 : if (err) {
1787 : DPRINTF("%s: dmamap_create: failed %d\n", DEVNAME(sc), err);
1788 : goto err_unmap;
1789 : }
1790 0 : err = bus_dmamap_load(sc->pci_dmat, buf->map, buf->addr,
1791 : buf->size, NULL, wait);
1792 0 : if (err) {
1793 : DPRINTF("%s: dmamap_load: failed %d\n", DEVNAME(sc), err);
1794 : goto err_destroy;
1795 : }
1796 0 : dma_addr = buf->map->dm_segs[0].ds_addr;
1797 : DPRINTF("%s: allocated %zd bytes dir=%d, ka=%p, da=%lx\n", DEVNAME(sc),
1798 : buf->size, dir, buf->addr, dma_addr);
1799 0 : if (!sc->isht && (dma_addr & ~ENVY_MAXADDR)) {
1800 0 : printf("%s: DMA address beyond 0x10000000\n", DEVNAME(sc));
1801 : goto err_unload;
1802 : }
1803 0 : return buf->addr;
1804 : err_unload:
1805 0 : bus_dmamap_unload(sc->pci_dmat, buf->map);
1806 : err_destroy:
1807 0 : bus_dmamap_destroy(sc->pci_dmat, buf->map);
1808 : err_unmap:
1809 0 : uvm_km_free(kernel_map, (vaddr_t)buf->addr, buf->size);
1810 : err_ret:
1811 0 : return NULL;
1812 0 : }
1813 :
1814 : void
1815 0 : envy_freem(void *self, void *addr, int type)
1816 : {
1817 : struct envy_buf *buf;
1818 0 : struct envy_softc *sc = (struct envy_softc *)self;
1819 : int dir;
1820 :
1821 0 : if (sc->ibuf.addr == addr) {
1822 : buf = &sc->ibuf;
1823 : dir = AUMODE_RECORD;
1824 0 : } else if (sc->obuf.addr == addr) {
1825 : buf = &sc->obuf;
1826 : dir = AUMODE_PLAY;
1827 : } else {
1828 : DPRINTF("%s: no buf to free\n", DEVNAME(sc));
1829 0 : return;
1830 : }
1831 0 : bus_dmamap_unload(sc->pci_dmat, buf->map);
1832 0 : bus_dmamap_destroy(sc->pci_dmat, buf->map);
1833 0 : uvm_km_free(kernel_map, (vaddr_t)&buf->addr, buf->size);
1834 0 : buf->addr = NULL;
1835 : DPRINTF("%s: freed buffer (mode=%d)\n", DEVNAME(sc), dir);
1836 0 : }
1837 :
1838 : int
1839 0 : envy_set_params(void *self, int setmode, int usemode,
1840 : struct audio_params *p, struct audio_params *r)
1841 : {
1842 0 : struct envy_softc *sc = (struct envy_softc *)self;
1843 : int i, rate, reg;
1844 :
1845 0 : if (setmode == 0)
1846 0 : return 0;
1847 0 : if (setmode == (AUMODE_PLAY | AUMODE_RECORD) &&
1848 0 : p->sample_rate != r->sample_rate) {
1849 : DPRINTF("%s: play/rec rates mismatch\n", DEVNAME(sc));
1850 0 : r->sample_rate = p->sample_rate;
1851 0 : }
1852 0 : rate = (setmode & AUMODE_PLAY) ? p->sample_rate : r->sample_rate;
1853 0 : for (i = 0; envy_rates[i].rate < rate; i++) {
1854 0 : if (envy_rates[i].rate == -1) {
1855 0 : i--;
1856 : DPRINTF("%s: rate: %d -> %d\n", DEVNAME(sc), rate, i);
1857 0 : break;
1858 : }
1859 : }
1860 0 : reg = envy_mt_read_1(sc, ENVY_MT_RATE);
1861 0 : reg &= ~ENVY_MT_RATEMASK;
1862 0 : reg |= envy_rates[i].reg;
1863 0 : envy_mt_write_1(sc, ENVY_MT_RATE, reg);
1864 0 : if (setmode & AUMODE_PLAY) {
1865 0 : p->sample_rate = envy_rates[i].rate;
1866 0 : p->encoding = AUDIO_ENCODING_SLINEAR_LE;
1867 0 : p->precision = 24;
1868 0 : p->bps = 4;
1869 0 : p->msb = 1;
1870 0 : p->channels = sc->isht ? sc->card->noch : ENVY_PCHANS;
1871 0 : }
1872 0 : if (setmode & AUMODE_RECORD) {
1873 0 : r->sample_rate = envy_rates[i].rate;
1874 0 : r->encoding = AUDIO_ENCODING_SLINEAR_LE;
1875 0 : r->precision = 24;
1876 0 : r->bps = 4;
1877 0 : r->msb = 1;
1878 0 : r->channels = sc->isht ? sc->card->nich : ENVY_RCHANS;
1879 0 : }
1880 0 : return 0;
1881 0 : }
1882 :
1883 : int
1884 0 : envy_round_blocksize(void *self, int blksz)
1885 : {
1886 0 : return (blksz + 0x1f) & ~0x1f;
1887 : }
1888 :
1889 : #ifdef ENVY_DEBUG
1890 : void
1891 : envy_pintr(struct envy_softc *sc)
1892 : {
1893 : int i;
1894 :
1895 : if (sc->spurious > 0 || envydebug >= 2) {
1896 : printf("%s: spurious = %u, start = %lld.%ld\n",
1897 : DEVNAME(sc), sc->spurious,
1898 : (long long)sc->start_ts.tv_sec, sc->start_ts.tv_nsec);
1899 : for (i = 0; i < sc->nintr; i++) {
1900 : printf("%lld.%09ld: "
1901 : "active=%d/%d pos=%d/%d st=%x/%x, ctl=%x\n",
1902 : (long long)sc->intrs[i].ts.tv_sec,
1903 : sc->intrs[i].ts.tv_nsec,
1904 : sc->intrs[i].iactive,
1905 : sc->intrs[i].oactive,
1906 : sc->intrs[i].ipos,
1907 : sc->intrs[i].opos,
1908 : sc->intrs[i].st,
1909 : sc->intrs[i].mask,
1910 : sc->intrs[i].ctl);
1911 : }
1912 : }
1913 : }
1914 : #endif
1915 :
1916 : int
1917 0 : envy_intr(void *self)
1918 : {
1919 0 : struct envy_softc *sc = (struct envy_softc *)self;
1920 : unsigned int reg, hwpos, cnt;
1921 : int mintr, mstat, mdata;
1922 : int st, err, ctl;
1923 : int max;
1924 :
1925 0 : mtx_enter(&audio_lock);
1926 0 : st = envy_mt_read_1(sc, ENVY_MT_INTR);
1927 0 : mintr = envy_ccs_read(sc, ENVY_CCS_INTSTAT);
1928 0 : if (!(st & ENVY_MT_INTR_ALL) && !(mintr & ENVY_CCS_INT_MIDI0)) {
1929 0 : mtx_leave(&audio_lock);
1930 0 : return 0;
1931 : }
1932 0 : if (st & ENVY_MT_INTR_ERR) {
1933 0 : err = envy_mt_read_1(sc, ENVY_MT_ERR);
1934 0 : envy_mt_write_1(sc, ENVY_MT_ERR, err);
1935 0 : }
1936 0 : envy_mt_write_1(sc, ENVY_MT_INTR, st);
1937 0 : envy_ccs_write(sc, ENVY_CCS_INTSTAT, mintr);
1938 :
1939 : #ifdef ENVY_DEBUG
1940 : if (sc->nintr < ENVY_NINTR) {
1941 : sc->intrs[sc->nintr].iactive = sc->iactive;
1942 : sc->intrs[sc->nintr].oactive = sc->oactive;
1943 : sc->intrs[sc->nintr].st = st;
1944 : sc->intrs[sc->nintr].ipos = envy_mt_read_2(sc, ENVY_MT_RBUFSZ);
1945 : sc->intrs[sc->nintr].opos = envy_mt_read_2(sc, ENVY_MT_PBUFSZ);
1946 : sc->intrs[sc->nintr].ctl = envy_mt_read_1(sc, ENVY_MT_CTL);
1947 : sc->intrs[sc->nintr].mask = envy_mt_read_1(sc, ENVY_MT_IMASK);
1948 : nanouptime(&sc->intrs[sc->nintr].ts);
1949 : sc->nintr++;
1950 : }
1951 : #endif
1952 0 : if (mintr & ENVY_CCS_INT_MIDI0) {
1953 0 : for (max = 128; max > 0; max--) {
1954 0 : mstat = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
1955 0 : if (mstat & ENVY_MIDISTAT_IEMPTY(sc))
1956 : break;
1957 0 : mdata = envy_ccs_read(sc, ENVY_CCS_MIDIDATA0);
1958 : #if NMIDI > 0
1959 0 : if (sc->midi_in)
1960 0 : sc->midi_in(sc->midi_arg, mdata);
1961 : #endif
1962 : }
1963 : }
1964 0 : if (st & ENVY_MT_INTR_PACK) {
1965 0 : if (sc->oactive) {
1966 0 : reg = envy_mt_read_2(sc, ENVY_MT_PBUFSZ);
1967 0 : hwpos = sc->obuf.bufsz - 4 * (reg + 1);
1968 0 : if (hwpos >= sc->obuf.bufsz)
1969 0 : hwpos -= sc->obuf.bufsz;
1970 : DPRINTFN(2, "%s: play: reg = %u, pos: %u -> %u\n",
1971 : DEVNAME(sc), reg, sc->obuf.swpos, hwpos);
1972 : cnt = 0;
1973 0 : while (hwpos - sc->obuf.swpos >= sc->obuf.blksz) {
1974 0 : sc->ointr(sc->oarg);
1975 0 : sc->obuf.swpos += sc->obuf.blksz;
1976 0 : if (sc->obuf.swpos == sc->obuf.bufsz)
1977 0 : sc->obuf.swpos = 0;
1978 0 : cnt++;
1979 : }
1980 : if (cnt != 1) {
1981 : DPRINTFN(2, "%s: play: %u intrs\n",
1982 : DEVNAME(sc), cnt);
1983 : }
1984 0 : } else {
1985 0 : ctl = envy_mt_read_1(sc, ENVY_MT_CTL);
1986 0 : if (ctl & ENVY_MT_CTL_PSTART) {
1987 0 : envy_mt_write_1(sc,
1988 0 : ENVY_MT_CTL, ctl & ~ENVY_MT_CTL_PSTART);
1989 0 : st &= ~ENVY_MT_INTR_PACK;
1990 0 : sc->obusy = 0;
1991 0 : wakeup(&sc->obusy);
1992 0 : }
1993 : #ifdef ENVY_DEBUG
1994 : else
1995 : sc->spurious++;
1996 : #endif
1997 : }
1998 : }
1999 0 : if (st & ENVY_MT_INTR_RACK) {
2000 0 : if (sc->iactive) {
2001 0 : reg = envy_mt_read_2(sc, ENVY_MT_RBUFSZ);
2002 0 : hwpos = sc->ibuf.bufsz - 4 * (reg + 1);
2003 0 : if (hwpos >= sc->ibuf.bufsz)
2004 0 : hwpos -= sc->ibuf.bufsz;
2005 : DPRINTFN(2, "%s: rec: reg = %u, pos: %u -> %u\n",
2006 : DEVNAME(sc), reg, sc->ibuf.swpos, hwpos);
2007 : cnt = 0;
2008 0 : while (hwpos - sc->ibuf.swpos >= sc->ibuf.blksz) {
2009 0 : sc->iintr(sc->iarg);
2010 0 : sc->ibuf.swpos += sc->ibuf.blksz;
2011 0 : if (sc->ibuf.swpos == sc->ibuf.bufsz)
2012 0 : sc->ibuf.swpos = 0;
2013 0 : cnt++;
2014 : }
2015 : if (cnt != 1) {
2016 : DPRINTFN(2, "%s: rec: %u intrs\n",
2017 : DEVNAME(sc), cnt);
2018 : }
2019 0 : } else {
2020 0 : ctl = envy_mt_read_1(sc, ENVY_MT_CTL);
2021 0 : if (ctl & ENVY_MT_CTL_RSTART(sc)) {
2022 0 : envy_mt_write_1(sc,
2023 0 : ENVY_MT_CTL, ctl & ~ENVY_MT_CTL_RSTART(sc));
2024 : st &= ~ENVY_MT_INTR_RACK;
2025 0 : sc->ibusy = 0;
2026 0 : wakeup(&sc->ibusy);
2027 0 : }
2028 : #ifdef ENVY_DEBUG
2029 : else
2030 : sc->spurious++;
2031 : #endif
2032 : }
2033 : }
2034 0 : mtx_leave(&audio_lock);
2035 0 : return 1;
2036 0 : }
2037 :
2038 : int
2039 0 : envy_trigger_output(void *self, void *start, void *end, int blksz,
2040 : void (*intr)(void *), void *arg, struct audio_params *param)
2041 : {
2042 0 : struct envy_softc *sc = (struct envy_softc *)self;
2043 : size_t bufsz;
2044 : int st;
2045 :
2046 0 : bufsz = (char *)end - (char *)start;
2047 : #ifdef ENVY_DEBUG
2048 : if (blksz % (sc->isht ? sc->card->noch * 4 : ENVY_PFRAME_SIZE) != 0) {
2049 : printf("%s: %d: bad output blksz\n", DEVNAME(sc), blksz);
2050 : return EINVAL;
2051 : }
2052 : if (bufsz % blksz) {
2053 : printf("%s: %ld: bad output bufsz\n", DEVNAME(sc), bufsz);
2054 : return EINVAL;
2055 : }
2056 : #endif
2057 0 : mtx_enter(&audio_lock);
2058 0 : envy_mt_write_4(sc, ENVY_MT_PADDR, sc->obuf.map->dm_segs[0].ds_addr);
2059 0 : envy_mt_write_2(sc, ENVY_MT_PBUFSZ, bufsz / 4 - 1);
2060 0 : envy_mt_write_2(sc, ENVY_MT_PBLKSZ(sc), blksz / 4 - 1);
2061 :
2062 : #ifdef ENVY_DEBUG
2063 : if (!sc->iactive) {
2064 : sc->nintr = 0;
2065 : sc->spurious = 0;
2066 : nanouptime(&sc->start_ts);
2067 : }
2068 : #endif
2069 0 : sc->obuf.bufsz = bufsz;
2070 0 : sc->obuf.blksz = blksz;
2071 0 : sc->obuf.swpos = 0;
2072 0 : sc->ointr = intr;
2073 0 : sc->oarg = arg;
2074 0 : sc->oactive = 1;
2075 0 : sc->obusy = 1;
2076 : st = ENVY_MT_INTR_PACK;
2077 0 : envy_mt_write_1(sc, ENVY_MT_INTR, st);
2078 0 : st = envy_mt_read_1(sc, ENVY_MT_CTL);
2079 0 : st |= ENVY_MT_CTL_PSTART;
2080 0 : envy_mt_write_1(sc, ENVY_MT_CTL, st);
2081 0 : mtx_leave(&audio_lock);
2082 0 : return 0;
2083 : }
2084 :
2085 : int
2086 0 : envy_trigger_input(void *self, void *start, void *end, int blksz,
2087 : void (*intr)(void *), void *arg, struct audio_params *param)
2088 : {
2089 0 : struct envy_softc *sc = (struct envy_softc *)self;
2090 : size_t bufsz;
2091 : int st;
2092 :
2093 0 : bufsz = (char *)end - (char *)start;
2094 : #ifdef ENVY_DEBUG
2095 : if (blksz % (sc->isht ? sc->card->nich * 4 : ENVY_RFRAME_SIZE) != 0) {
2096 : printf("%s: %d: bad input blksz\n", DEVNAME(sc), blksz);
2097 : return EINVAL;
2098 : }
2099 : if (bufsz % blksz != 0) {
2100 : printf("%s: %ld: bad input bufsz\n", DEVNAME(sc), bufsz);
2101 : return EINVAL;
2102 : }
2103 : #endif
2104 0 : mtx_enter(&audio_lock);
2105 0 : envy_mt_write_4(sc, ENVY_MT_RADDR, sc->ibuf.map->dm_segs[0].ds_addr);
2106 0 : envy_mt_write_2(sc, ENVY_MT_RBUFSZ, bufsz / 4 - 1);
2107 0 : envy_mt_write_2(sc, ENVY_MT_RBLKSZ, blksz / 4 - 1);
2108 :
2109 : #ifdef ENVY_DEBUG
2110 : if (!sc->oactive) {
2111 : sc->nintr = 0;
2112 : sc->spurious = 0;
2113 : nanouptime(&sc->start_ts);
2114 : }
2115 : #endif
2116 0 : sc->ibuf.bufsz = bufsz;
2117 0 : sc->ibuf.blksz = blksz;
2118 0 : sc->ibuf.swpos = 0;
2119 0 : sc->iintr = intr;
2120 0 : sc->iarg = arg;
2121 0 : sc->iactive = 1;
2122 0 : sc->ibusy = 1;
2123 : st = ENVY_MT_INTR_RACK;
2124 0 : envy_mt_write_1(sc, ENVY_MT_INTR, st);
2125 0 : st = envy_mt_read_1(sc, ENVY_MT_CTL);
2126 0 : st |= ENVY_MT_CTL_RSTART(sc);
2127 0 : envy_mt_write_1(sc, ENVY_MT_CTL, st);
2128 0 : mtx_leave(&audio_lock);
2129 0 : return 0;
2130 : }
2131 :
2132 : int
2133 0 : envy_halt_output(void *self)
2134 : {
2135 0 : struct envy_softc *sc = (struct envy_softc *)self;
2136 : int err;
2137 :
2138 0 : mtx_enter(&audio_lock);
2139 0 : sc->oactive = 0;
2140 0 : if (sc->obusy) {
2141 0 : err = msleep(&sc->obusy, &audio_lock, PWAIT, "envyobus", 4 * hz);
2142 0 : if (err)
2143 0 : printf("%s: output DMA halt timeout\n", DEVNAME(sc));
2144 : }
2145 : #ifdef ENVY_DEBUG
2146 : if (!sc->iactive)
2147 : envy_pintr(sc);
2148 : #endif
2149 0 : mtx_leave(&audio_lock);
2150 0 : return 0;
2151 : }
2152 :
2153 : int
2154 0 : envy_halt_input(void *self)
2155 : {
2156 0 : struct envy_softc *sc = (struct envy_softc *)self;
2157 : int err;
2158 :
2159 0 : mtx_enter(&audio_lock);
2160 0 : sc->iactive = 0;
2161 0 : if (sc->ibusy) {
2162 0 : err = msleep(&sc->ibusy, &audio_lock, PWAIT, "envyibus", 4 * hz);
2163 0 : if (err)
2164 0 : printf("%s: input DMA halt timeout\n", DEVNAME(sc));
2165 : }
2166 : #ifdef ENVY_DEBUG
2167 : if (!sc->oactive)
2168 : envy_pintr(sc);
2169 : #endif
2170 0 : mtx_leave(&audio_lock);
2171 0 : return 0;
2172 : }
2173 :
2174 : int
2175 0 : envy_query_devinfo(void *self, struct mixer_devinfo *dev)
2176 : {
2177 0 : struct envy_softc *sc = (struct envy_softc *)self;
2178 : int i, n, idx, ndev;
2179 0 : char *classes[] = {
2180 : AudioCinputs, AudioCoutputs, AudioCmonitor
2181 : };
2182 :
2183 0 : if (sc->isac97)
2184 0 : return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dev));
2185 :
2186 0 : if (dev->index < 0)
2187 0 : return ENXIO;
2188 :
2189 : idx = dev->index;
2190 : ndev = ENVY_MIX_NCLASS;
2191 0 : dev->prev = dev->next = AUDIO_MIXER_LAST;
2192 :
2193 : /*
2194 : * classes
2195 : */
2196 0 : if (idx < ndev) {
2197 0 : dev->type = AUDIO_MIXER_CLASS;
2198 0 : dev->mixer_class = idx;
2199 0 : strlcpy(dev->label.name, classes[idx], MAX_AUDIO_DEV_LEN);
2200 0 : return 0;
2201 : }
2202 0 : idx -= ndev;
2203 :
2204 : /*
2205 : * output.lineX_source
2206 : */
2207 0 : ndev = sc->card->noch;
2208 0 : if (idx < ndev) {
2209 : n = 0;
2210 0 : dev->type = AUDIO_MIXER_ENUM;
2211 0 : dev->mixer_class = ENVY_MIX_CLASSOUT;
2212 0 : for (i = 0; i < sc->card->nich; i++) {
2213 : dev->un.e.member[n].ord = n;
2214 0 : snprintf(dev->un.e.member[n++].label.name,
2215 : MAX_AUDIO_DEV_LEN, AudioNline "-%d", i);
2216 : }
2217 : dev->un.e.member[n].ord = n;
2218 0 : snprintf(dev->un.e.member[n++].label.name,
2219 : MAX_AUDIO_DEV_LEN, "play-%d", idx);
2220 0 : if (!sc->isht && idx < 2) {
2221 0 : dev->un.e.member[n].ord = n;
2222 0 : snprintf(dev->un.e.member[n++].label.name,
2223 : MAX_AUDIO_DEV_LEN, "mon-%d", idx);
2224 0 : }
2225 0 : snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
2226 : AudioNline "-%d_" AudioNsource, idx);
2227 0 : dev->un.s.num_mem = n;
2228 0 : return 0;
2229 : }
2230 0 : idx -= ndev;
2231 :
2232 : /*
2233 : * envy monitor level
2234 : */
2235 0 : ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
2236 0 : if (idx < ndev) {
2237 0 : dev->type = AUDIO_MIXER_VALUE;
2238 0 : dev->mixer_class = ENVY_MIX_CLASSMON;
2239 0 : dev->un.v.delta = 2;
2240 0 : dev->un.v.num_channels = 1;
2241 0 : snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
2242 0 : "%s-%d", idx < 10 ? "play" : "rec", idx % 10);
2243 0 : strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN);
2244 0 : return 0;
2245 : }
2246 0 : idx -= ndev;
2247 :
2248 : /*
2249 : * inputs.xxx
2250 : */
2251 0 : ndev = sc->card->adc->ndev(sc);
2252 0 : if (idx < ndev) {
2253 0 : sc->card->adc->devinfo(sc, dev, idx);
2254 0 : return 0;
2255 : }
2256 0 : idx -= ndev;
2257 :
2258 : /*
2259 : * outputs.xxx
2260 : */
2261 0 : ndev = sc->card->dac->ndev(sc);
2262 0 : if (idx < ndev) {
2263 0 : sc->card->dac->devinfo(sc, dev, idx);
2264 0 : return 0;
2265 : }
2266 0 : return ENXIO;
2267 0 : }
2268 :
2269 : int
2270 0 : envy_get_port(void *self, struct mixer_ctrl *ctl)
2271 : {
2272 0 : struct envy_softc *sc = (struct envy_softc *)self;
2273 0 : int val, idx, ndev;
2274 :
2275 0 : if (sc->isac97)
2276 0 : return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, ctl));
2277 :
2278 0 : if (ctl->dev < ENVY_MIX_NCLASS) {
2279 0 : return EINVAL;
2280 : }
2281 :
2282 0 : idx = ctl->dev - ENVY_MIX_NCLASS;
2283 0 : ndev = sc->card->noch;
2284 0 : if (idx < ndev) {
2285 0 : ctl->un.ord = envy_lineout_getsrc(sc, idx);
2286 0 : if (ctl->un.ord >= ENVY_MIX_NOUTSRC)
2287 0 : ctl->un.ord -= ENVY_MIX_NOUTSRC - sc->card->nich;
2288 0 : return 0;
2289 : }
2290 0 : idx -= ndev;
2291 0 : ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
2292 0 : if (idx < ndev) {
2293 0 : envy_mon_getvol(sc, idx / 2, idx % 2, &val);
2294 0 : ctl->un.value.num_channels = 1;
2295 0 : ctl->un.value.level[0] = 2 * val;
2296 0 : return 0;
2297 : }
2298 0 : idx -= ndev;
2299 0 : ndev = sc->card->adc->ndev(sc);
2300 0 : if (idx < ndev) {
2301 0 : sc->card->adc->get(sc, ctl, idx);
2302 0 : return 0;
2303 : }
2304 0 : idx -= ndev;
2305 0 : ndev = sc->card->dac->ndev(sc);
2306 0 : if (idx < ndev) {
2307 0 : sc->card->dac->get(sc, ctl, idx);
2308 0 : return 0;
2309 : }
2310 0 : return ENXIO;
2311 0 : }
2312 :
2313 : int
2314 0 : envy_set_port(void *self, struct mixer_ctrl *ctl)
2315 : {
2316 0 : struct envy_softc *sc = (struct envy_softc *)self;
2317 : int maxsrc, val, idx, ndev;
2318 :
2319 0 : if (sc->isac97)
2320 0 : return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, ctl));
2321 :
2322 0 : if (ctl->dev < ENVY_MIX_NCLASS) {
2323 0 : return EINVAL;
2324 : }
2325 :
2326 0 : idx = ctl->dev - ENVY_MIX_NCLASS;
2327 0 : ndev = sc->card->noch;
2328 0 : if (idx < ndev) {
2329 0 : maxsrc = sc->card->nich + 1;
2330 0 : if (idx < 2)
2331 0 : maxsrc++;
2332 0 : if (ctl->un.ord < 0 || ctl->un.ord >= maxsrc)
2333 0 : return EINVAL;
2334 0 : if (ctl->un.ord >= sc->card->nich)
2335 0 : ctl->un.ord += ENVY_MIX_NOUTSRC - sc->card->nich;
2336 0 : envy_lineout_setsrc(sc, idx, ctl->un.ord);
2337 0 : return 0;
2338 : }
2339 0 : idx -= ndev;
2340 0 : ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
2341 0 : if (idx < ndev) {
2342 0 : if (ctl->un.value.num_channels != 1) {
2343 0 : return EINVAL;
2344 : }
2345 0 : val = ctl->un.value.level[0] / 2;
2346 0 : envy_mon_setvol(sc, idx / 2, idx % 2, val);
2347 0 : return 0;
2348 : }
2349 0 : idx -= ndev;
2350 0 : ndev = sc->card->adc->ndev(sc);
2351 0 : if (idx < ndev)
2352 0 : return sc->card->adc->set(sc, ctl, idx);
2353 0 : idx -= ndev;
2354 0 : ndev = sc->card->dac->ndev(sc);
2355 0 : if (idx < ndev)
2356 0 : return sc->card->dac->set(sc, ctl, idx);
2357 0 : return ENXIO;
2358 0 : }
2359 :
2360 : int
2361 0 : envy_get_props(void *self)
2362 : {
2363 0 : return AUDIO_PROP_FULLDUPLEX | AUDIO_PROP_INDEPENDENT;
2364 : }
2365 :
2366 : #if NMIDI > 0
2367 : int
2368 0 : envy_midi_open(void *self, int flags,
2369 : void (*in)(void *, int),
2370 : void (*out)(void *),
2371 : void *arg)
2372 : {
2373 0 : struct envy_softc *sc = (struct envy_softc *)self;
2374 : unsigned int i, reg;
2375 :
2376 : /* discard pending data */
2377 0 : for (i = 0; i < 128; i++) {
2378 0 : reg = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
2379 0 : if (reg & ENVY_MIDISTAT_IEMPTY(sc))
2380 : break;
2381 0 : (void)envy_ccs_read(sc, ENVY_CCS_MIDIDATA0);
2382 : }
2383 : #ifdef ENVY_DEBUG
2384 : if (i > 0)
2385 : DPRINTF("%s: midi: discarded %u bytes\n", DEVNAME(sc), i);
2386 : #endif
2387 :
2388 : /* clear pending midi interrupt */
2389 0 : envy_ccs_write(sc, ENVY_CCS_INTSTAT, ENVY_CCS_INT_MIDI0);
2390 :
2391 : /* interrupts are disabled, it safe to manipulate these */
2392 0 : sc->midi_in = in;
2393 0 : sc->midi_out = out;
2394 0 : sc->midi_arg = arg;
2395 0 : sc->midi_isopen = 1;
2396 :
2397 : /* enable interrupts */
2398 0 : reg = envy_ccs_read(sc, ENVY_CCS_INTMASK);
2399 0 : reg &= ~ENVY_CCS_INT_MIDI0;
2400 0 : envy_ccs_write(sc, ENVY_CCS_INTMASK, reg);
2401 0 : return 0;
2402 : }
2403 :
2404 : void
2405 0 : envy_midi_close(void *self)
2406 : {
2407 0 : struct envy_softc *sc = (struct envy_softc *)self;
2408 : unsigned int reg;
2409 :
2410 : /* wait for output fifo to drain */
2411 0 : tsleep(sc, PWAIT, "envymid", hz / 10);
2412 :
2413 : /* disable interrupts */
2414 0 : reg = envy_ccs_read(sc, ENVY_CCS_INTMASK);
2415 0 : reg |= ENVY_CCS_INT_MIDI0;
2416 0 : envy_ccs_write(sc, ENVY_CCS_INTMASK, reg);
2417 :
2418 : /* interrupts are disabled, it safe to manipulate these */
2419 0 : sc->midi_in = NULL;
2420 0 : sc->midi_out = NULL;
2421 0 : sc->midi_isopen = 0;
2422 0 : }
2423 :
2424 : int
2425 0 : envy_midi_output(void *self, int data)
2426 : {
2427 0 : struct envy_softc *sc = (struct envy_softc *)self;
2428 : int st;
2429 :
2430 0 : st = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
2431 0 : if (st & ENVY_MIDISTAT_OBUSY(sc))
2432 0 : return 0;
2433 0 : envy_ccs_write(sc, ENVY_CCS_MIDIDATA0, data);
2434 0 : return 1;
2435 0 : }
2436 :
2437 : void
2438 0 : envy_midi_getinfo(void *self, struct midi_info *mi)
2439 : {
2440 0 : mi->props = MIDI_PROP_CAN_INPUT;
2441 0 : mi->name = "Envy24 MIDI UART";
2442 0 : }
2443 : #endif
|