Line data Source code
1 : /* $OpenBSD: eap.c,v 1.56 2018/09/14 08:37:34 miko Exp $ */
2 : /* $NetBSD: eap.c,v 1.46 2001/09/03 15:07:37 reinoud Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
6 : * All rights reserved.
7 : *
8 : * This code is derived from software contributed to The NetBSD Foundation
9 : * by Lennart Augustsson <augustss@netbsd.org> and Charles M. Hannum.
10 : *
11 : * Redistribution and use in source and binary forms, with or without
12 : * modification, are permitted provided that the following conditions
13 : * are met:
14 : * 1. Redistributions of source code must retain the above copyright
15 : * notice, this list of conditions and the following disclaimer.
16 : * 2. Redistributions in binary form must reproduce the above copyright
17 : * notice, this list of conditions and the following disclaimer in the
18 : * documentation and/or other materials provided with the distribution.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 : * POSSIBILITY OF SUCH DAMAGE.
31 : */
32 :
33 : /*
34 : * Debugging: Andreas Gustafsson <gson@araneus.fi>
35 : * Testing: Chuck Cranor <chuck@maria.wustl.edu>
36 : * Phil Nelson <phil@cs.wwu.edu>
37 : *
38 : * ES1371/AC97: Ezra Story <ezy@panix.com>
39 : */
40 :
41 : /*
42 : * Ensoniq ES1370 + AK4531 and ES1371/ES1373 + AC97
43 : *
44 : * Documentation links:
45 : *
46 : * ftp://ftp.alsa-project.org/pub/manuals/ensoniq/
47 : * ftp://ftp.alsa-project.org/pub/manuals/asahi_kasei/4531.pdf
48 : */
49 :
50 : #include "midi.h"
51 :
52 : #include <sys/param.h>
53 : #include <sys/systm.h>
54 : #include <sys/kernel.h>
55 : #include <sys/fcntl.h>
56 : #include <sys/device.h>
57 :
58 : #include <dev/pci/pcidevs.h>
59 : #include <dev/pci/pcivar.h>
60 :
61 : #include <sys/audioio.h>
62 : #include <dev/audio_if.h>
63 : #include <dev/midi_if.h>
64 : #include <dev/ic/ac97.h>
65 :
66 : #include <machine/bus.h>
67 :
68 : #include <dev/pci/eapreg.h>
69 :
70 : struct cfdriver eap_cd = {
71 : NULL, "eap", DV_DULL
72 : };
73 :
74 : #define PCI_CBIO 0x10
75 :
76 : /* Debug */
77 : #ifdef AUDIO_DEBUG
78 : #define DPRINTF(x) if (eapdebug) printf x
79 : #define DPRINTFN(n,x) if (eapdebug>(n)) printf x
80 : int eapdebug = 1;
81 : #else
82 : #define DPRINTF(x)
83 : #define DPRINTFN(n,x)
84 : #endif
85 :
86 : int eap_match(struct device *, void *, void *);
87 : void eap_attach(struct device *, struct device *, void *);
88 : int eap_activate(struct device *, int);
89 : int eap_intr(void *);
90 :
91 : struct eap_dma {
92 : bus_dmamap_t map;
93 : caddr_t addr;
94 : bus_dma_segment_t segs[1];
95 : int nsegs;
96 : size_t size;
97 : struct eap_dma *next;
98 : };
99 :
100 : #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
101 : #define KERNADDR(p) ((void *)((p)->addr))
102 :
103 : struct eap_softc {
104 : struct device sc_dev; /* base device */
105 : void *sc_ih; /* interrupt vectoring */
106 : bus_space_tag_t iot;
107 : bus_space_handle_t ioh;
108 : bus_dma_tag_t sc_dmatag; /* DMA tag */
109 :
110 : struct eap_dma *sc_dmas;
111 :
112 : void (*sc_pintr)(void *); /* dma completion intr handler */
113 : void *sc_parg; /* arg for sc_intr() */
114 : #ifdef DIAGNOSTIC
115 : char sc_prun;
116 : #endif
117 :
118 : void (*sc_rintr)(void *); /* dma completion intr handler */
119 : void *sc_rarg; /* arg for sc_intr() */
120 : #ifdef DIAGNOSTIC
121 : char sc_rrun;
122 : #endif
123 :
124 : #if NMIDI > 0
125 : void (*sc_iintr)(void *, int); /* midi input ready handler */
126 : void (*sc_ointr)(void *); /* midi output ready handler */
127 : void *sc_arg;
128 : int sc_uctrl;
129 : struct device *sc_mididev;
130 : #endif
131 :
132 : u_short sc_port[AK_NPORTS]; /* mirror of the hardware setting */
133 : u_int sc_record_source; /* recording source mask */
134 : u_int sc_input_source; /* input source mask */
135 : u_int sc_mic_preamp;
136 : char sc_1371; /* Using ES1371/AC97 codec */
137 : char sc_ct5880; /* CT5880 chip */
138 :
139 : struct ac97_codec_if *codec_if;
140 : struct ac97_host_if host_if;
141 :
142 : int flags;
143 : };
144 :
145 : enum ac97_host_flags eap_flags_codec(void *);
146 : int eap_allocmem(struct eap_softc *, size_t, size_t, struct eap_dma *);
147 : int eap_freemem(struct eap_softc *, struct eap_dma *);
148 :
149 : #define EWRITE1(sc, r, x) bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x))
150 : #define EWRITE2(sc, r, x) bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x))
151 : #define EWRITE4(sc, r, x) bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x))
152 : #define EREAD1(sc, r) bus_space_read_1((sc)->iot, (sc)->ioh, (r))
153 : #define EREAD2(sc, r) bus_space_read_2((sc)->iot, (sc)->ioh, (r))
154 : #define EREAD4(sc, r) bus_space_read_4((sc)->iot, (sc)->ioh, (r))
155 :
156 : struct cfattach eap_ca = {
157 : sizeof(struct eap_softc), eap_match, eap_attach, NULL, eap_activate
158 : };
159 :
160 : int eap_open(void *, int);
161 : void eap_close(void *);
162 : int eap_set_params(void *, int, int, struct audio_params *, struct audio_params *);
163 : int eap_round_blocksize(void *, int);
164 : int eap_trigger_output(void *, void *, void *, int, void (*)(void *),
165 : void *, struct audio_params *);
166 : int eap_trigger_input(void *, void *, void *, int, void (*)(void *),
167 : void *, struct audio_params *);
168 : int eap_halt_output(void *);
169 : int eap_halt_input(void *);
170 : void eap_resume(struct eap_softc *);
171 : void eap1370_write_codec(struct eap_softc *, int, int);
172 : int eap1370_mixer_set_port(void *, mixer_ctrl_t *);
173 : int eap1370_mixer_get_port(void *, mixer_ctrl_t *);
174 : int eap1371_mixer_set_port(void *, mixer_ctrl_t *);
175 : int eap1371_mixer_get_port(void *, mixer_ctrl_t *);
176 : int eap1370_query_devinfo(void *, mixer_devinfo_t *);
177 : void *eap_malloc(void *, int, size_t, int, int);
178 : void eap_free(void *, void *, int);
179 : int eap_get_props(void *);
180 : void eap1370_set_mixer(struct eap_softc *sc, int a, int d);
181 : u_int32_t eap1371_src_wait(struct eap_softc *sc);
182 : void eap1371_src_write(struct eap_softc *sc, int a, int d);
183 : int eap1371_query_devinfo(void *addr, mixer_devinfo_t *dip);
184 :
185 : int eap1371_attach_codec(void *sc, struct ac97_codec_if *);
186 : int eap1371_read_codec(void *sc, u_int8_t a, u_int16_t *d);
187 : int eap1371_write_codec(void *sc, u_int8_t a, u_int16_t d);
188 : void eap1371_reset_codec(void *sc);
189 : #if NMIDI > 0
190 : void eap_midi_close(void *);
191 : void eap_midi_getinfo(void *, struct midi_info *);
192 : int eap_midi_open(void *, int, void (*)(void *, int),
193 : void (*)(void *), void *);
194 : int eap_midi_output(void *, int);
195 : #endif
196 :
197 : struct audio_hw_if eap1370_hw_if = {
198 : eap_open,
199 : eap_close,
200 : eap_set_params,
201 : eap_round_blocksize,
202 : NULL,
203 : NULL,
204 : NULL,
205 : NULL,
206 : NULL,
207 : eap_halt_output,
208 : eap_halt_input,
209 : NULL,
210 : NULL,
211 : eap1370_mixer_set_port,
212 : eap1370_mixer_get_port,
213 : eap1370_query_devinfo,
214 : eap_malloc,
215 : eap_free,
216 : NULL,
217 : eap_get_props,
218 : eap_trigger_output,
219 : eap_trigger_input
220 : };
221 :
222 : struct audio_hw_if eap1371_hw_if = {
223 : eap_open,
224 : eap_close,
225 : eap_set_params,
226 : eap_round_blocksize,
227 : NULL,
228 : NULL,
229 : NULL,
230 : NULL,
231 : NULL,
232 : eap_halt_output,
233 : eap_halt_input,
234 : NULL,
235 : NULL,
236 : eap1371_mixer_set_port,
237 : eap1371_mixer_get_port,
238 : eap1371_query_devinfo,
239 : eap_malloc,
240 : eap_free,
241 : NULL,
242 : eap_get_props,
243 : eap_trigger_output,
244 : eap_trigger_input
245 : };
246 :
247 : #if NMIDI > 0
248 : struct midi_hw_if eap_midi_hw_if = {
249 : eap_midi_open,
250 : eap_midi_close,
251 : eap_midi_output,
252 : 0, /* flush */
253 : eap_midi_getinfo,
254 : 0, /* ioctl */
255 : };
256 : #endif
257 :
258 : const struct pci_matchid eap_devices[] = {
259 : { PCI_VENDOR_CREATIVELABS, PCI_PRODUCT_CREATIVELABS_EV1938 },
260 : { PCI_VENDOR_ENSONIQ, PCI_PRODUCT_ENSONIQ_AUDIOPCI },
261 : { PCI_VENDOR_ENSONIQ, PCI_PRODUCT_ENSONIQ_AUDIOPCI97 },
262 : { PCI_VENDOR_ENSONIQ, PCI_PRODUCT_ENSONIQ_CT5880 },
263 : };
264 :
265 : int
266 0 : eap_match(struct device *parent, void *match, void *aux)
267 : {
268 0 : return (pci_matchbyid((struct pci_attach_args *)aux, eap_devices,
269 : nitems(eap_devices)));
270 : }
271 :
272 : int
273 0 : eap_activate(struct device *self, int act)
274 : {
275 0 : struct eap_softc *sc = (struct eap_softc *)self;
276 :
277 0 : switch (act) {
278 : case DVACT_RESUME:
279 0 : eap_resume(sc);
280 0 : break;
281 : default:
282 : break;
283 : }
284 0 : return (config_activate_children(self, act));
285 : }
286 :
287 : void
288 0 : eap1370_write_codec(struct eap_softc *sc, int a, int d)
289 : {
290 : int icss, to;
291 :
292 : to = EAP_WRITE_TIMEOUT;
293 0 : do {
294 0 : icss = EREAD4(sc, EAP_ICSS);
295 : DPRINTFN(5,("eap: codec %d prog: icss=0x%08x\n", a, icss));
296 0 : if (!to--) {
297 0 : printf("%s: timeout writing to codec\n",
298 0 : sc->sc_dev.dv_xname);
299 0 : return;
300 : }
301 0 : } while (icss & EAP_CWRIP); /* XXX could use CSTAT here */
302 0 : EWRITE4(sc, EAP_CODEC, EAP_SET_CODEC(a, d));
303 0 : }
304 :
305 : /*
306 : * Reading and writing the CODEC is very convoluted. This mimics the
307 : * FreeBSD and Linux drivers.
308 : */
309 :
310 : static __inline void
311 0 : eap1371_ready_codec(struct eap_softc *sc, u_int8_t a, u_int32_t wd)
312 : {
313 : int to;
314 : u_int32_t src, t;
315 :
316 0 : for (to = 0; to < EAP_WRITE_TIMEOUT; to++) {
317 0 : if (!(EREAD4(sc, E1371_CODEC) & E1371_CODEC_WIP))
318 : break;
319 0 : delay(1);
320 : }
321 0 : if (to == EAP_WRITE_TIMEOUT)
322 0 : printf("%s: eap1371_ready_codec timeout 1\n",
323 0 : sc->sc_dev.dv_xname);
324 :
325 0 : mtx_enter(&audio_lock);
326 0 : src = eap1371_src_wait(sc) & E1371_SRC_CTLMASK;
327 0 : EWRITE4(sc, E1371_SRC, src | E1371_SRC_STATE_OK);
328 :
329 0 : for (to = 0; to < EAP_READ_TIMEOUT; to++) {
330 0 : t = EREAD4(sc, E1371_SRC);
331 0 : if ((t & E1371_SRC_STATE_MASK) == 0)
332 : break;
333 0 : delay(1);
334 : }
335 0 : if (to == EAP_READ_TIMEOUT)
336 0 : printf("%s: eap1371_ready_codec timeout 2\n",
337 0 : sc->sc_dev.dv_xname);
338 :
339 0 : for (to = 0; to < EAP_READ_TIMEOUT; to++) {
340 0 : t = EREAD4(sc, E1371_SRC);
341 0 : if ((t & E1371_SRC_STATE_MASK) == E1371_SRC_STATE_OK)
342 : break;
343 0 : delay(1);
344 : }
345 0 : if (to == EAP_READ_TIMEOUT)
346 0 : printf("%s: eap1371_ready_codec timeout 3\n",
347 0 : sc->sc_dev.dv_xname);
348 :
349 0 : EWRITE4(sc, E1371_CODEC, wd);
350 :
351 0 : eap1371_src_wait(sc);
352 0 : EWRITE4(sc, E1371_SRC, src);
353 :
354 0 : mtx_leave(&audio_lock);
355 0 : }
356 :
357 : int
358 0 : eap1371_read_codec(void *sc_, u_int8_t a, u_int16_t *d)
359 : {
360 0 : struct eap_softc *sc = sc_;
361 : int to;
362 : u_int32_t t;
363 :
364 0 : eap1371_ready_codec(sc, a, E1371_SET_CODEC(a, 0) | E1371_CODEC_READ);
365 :
366 0 : for (to = 0; to < EAP_WRITE_TIMEOUT; to++) {
367 0 : if (!(EREAD4(sc, E1371_CODEC) & E1371_CODEC_WIP))
368 : break;
369 0 : delay(1);
370 : }
371 0 : if (to == EAP_WRITE_TIMEOUT)
372 0 : printf("%s: eap1371_read_codec timeout 1\n",
373 0 : sc->sc_dev.dv_xname);
374 :
375 0 : for (to = 0; to < EAP_WRITE_TIMEOUT; to++) {
376 0 : t = EREAD4(sc, E1371_CODEC);
377 0 : if (t & E1371_CODEC_VALID)
378 : break;
379 0 : delay(1);
380 : }
381 0 : if (to == EAP_WRITE_TIMEOUT)
382 0 : printf("%s: eap1371_read_codec timeout 2\n",
383 0 : sc->sc_dev.dv_xname);
384 :
385 0 : *d = (u_int16_t)t;
386 :
387 : DPRINTFN(10, ("eap1371: reading codec (%x) = %x\n", a, *d));
388 :
389 0 : return (0);
390 : }
391 :
392 : int
393 0 : eap1371_write_codec(void *sc_, u_int8_t a, u_int16_t d)
394 : {
395 0 : struct eap_softc *sc = sc_;
396 :
397 0 : eap1371_ready_codec(sc, a, E1371_SET_CODEC(a, d));
398 :
399 : DPRINTFN(10, ("eap1371: writing codec %x --> %x\n", d, a));
400 :
401 0 : return (0);
402 : }
403 :
404 : u_int32_t
405 0 : eap1371_src_wait(struct eap_softc *sc)
406 : {
407 : int to;
408 : u_int32_t src = 0;
409 :
410 0 : for (to = 0; to < EAP_READ_TIMEOUT; to++) {
411 0 : src = EREAD4(sc, E1371_SRC);
412 0 : if (!(src & E1371_SRC_RBUSY))
413 0 : return (src);
414 0 : delay(1);
415 : }
416 0 : printf("%s: eap1371_src_wait timeout\n", sc->sc_dev.dv_xname);
417 0 : return (src);
418 0 : }
419 :
420 : void
421 0 : eap1371_src_write(struct eap_softc *sc, int a, int d)
422 : {
423 : u_int32_t r;
424 :
425 0 : r = eap1371_src_wait(sc) & E1371_SRC_CTLMASK;
426 0 : r |= E1371_SRC_RAMWE | E1371_SRC_ADDR(a) | E1371_SRC_DATA(d);
427 0 : EWRITE4(sc, E1371_SRC, r);
428 0 : }
429 :
430 : void
431 0 : eap_attach(struct device *parent, struct device *self, void *aux)
432 : {
433 0 : struct eap_softc *sc = (struct eap_softc *)self;
434 0 : struct pci_attach_args *pa = (struct pci_attach_args *)aux;
435 0 : pci_chipset_tag_t pc = pa->pa_pc;
436 : struct audio_hw_if *eap_hw_if;
437 : char const *intrstr;
438 0 : pci_intr_handle_t ih;
439 0 : mixer_ctrl_t ctl;
440 : int i;
441 : int revision;
442 :
443 : /* Flag if we're "creative" */
444 0 : sc->sc_1371 = !(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ENSONIQ &&
445 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ENSONIQ_AUDIOPCI);
446 :
447 0 : revision = PCI_REVISION(pa->pa_class);
448 0 : if (sc->sc_1371) {
449 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ENSONIQ &&
450 0 : ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ENSONIQ_AUDIOPCI97 &&
451 0 : (revision == EAP_ES1373_8 || revision == EAP_CT5880_A)) ||
452 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ENSONIQ_CT5880))
453 0 : sc->sc_ct5880 = 1;
454 : }
455 :
456 : /* Map I/O register */
457 0 : if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
458 0 : &sc->iot, &sc->ioh, NULL, NULL, 0)) {
459 0 : return;
460 : }
461 :
462 0 : sc->sc_dmatag = pa->pa_dmat;
463 :
464 : /* Map and establish the interrupt. */
465 0 : if (pci_intr_map(pa, &ih)) {
466 0 : printf(": couldn't map interrupt\n");
467 0 : return;
468 : }
469 0 : intrstr = pci_intr_string(pc, ih);
470 0 : sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO | IPL_MPSAFE,
471 0 : eap_intr, sc, sc->sc_dev.dv_xname);
472 0 : if (sc->sc_ih == NULL) {
473 0 : printf(": couldn't establish interrupt");
474 0 : if (intrstr != NULL)
475 0 : printf(" at %s", intrstr);
476 0 : printf("\n");
477 0 : return;
478 : }
479 0 : printf(": %s\n", intrstr);
480 :
481 0 : if (!sc->sc_1371) {
482 : /* Enable interrupts and looping mode. */
483 : /* enable the parts we need */
484 0 : EWRITE4(sc, EAP_SIC, EAP_P2_INTR_EN | EAP_R1_INTR_EN);
485 0 : EWRITE4(sc, EAP_ICSC, EAP_CDC_EN);
486 :
487 : /* reset codec */
488 : /* normal operation */
489 : /* select codec clocks */
490 0 : eap1370_write_codec(sc, AK_RESET, AK_PD);
491 0 : eap1370_write_codec(sc, AK_RESET, AK_PD | AK_NRST);
492 0 : eap1370_write_codec(sc, AK_CS, 0x0);
493 :
494 : eap_hw_if = &eap1370_hw_if;
495 :
496 : /* Enable all relevant mixer switches. */
497 0 : ctl.dev = EAP_INPUT_SOURCE;
498 0 : ctl.type = AUDIO_MIXER_SET;
499 0 : ctl.un.mask = 1 << EAP_VOICE_VOL | 1 << EAP_FM_VOL |
500 : 1 << EAP_CD_VOL | 1 << EAP_LINE_VOL | 1 << EAP_AUX_VOL |
501 : 1 << EAP_MIC_VOL;
502 0 : eap_hw_if->set_port(sc, &ctl);
503 :
504 0 : ctl.type = AUDIO_MIXER_VALUE;
505 0 : ctl.un.value.num_channels = 1;
506 0 : for (ctl.dev = EAP_MASTER_VOL; ctl.dev < EAP_MIC_VOL;
507 0 : ctl.dev++) {
508 0 : ctl.un.value.level[AUDIO_MIXER_LEVEL_MONO] = VOL_0DB;
509 0 : eap_hw_if->set_port(sc, &ctl);
510 : }
511 0 : ctl.un.value.level[AUDIO_MIXER_LEVEL_MONO] = 0;
512 0 : eap_hw_if->set_port(sc, &ctl);
513 0 : ctl.dev = EAP_MIC_PREAMP;
514 0 : ctl.type = AUDIO_MIXER_ENUM;
515 0 : ctl.un.ord = 0;
516 0 : eap_hw_if->set_port(sc, &ctl);
517 0 : ctl.dev = EAP_RECORD_SOURCE;
518 0 : ctl.type = AUDIO_MIXER_SET;
519 0 : ctl.un.mask = 1 << EAP_MIC_VOL;
520 0 : eap_hw_if->set_port(sc, &ctl);
521 0 : } else {
522 : /* clean slate */
523 :
524 0 : EWRITE4(sc, EAP_SIC, 0);
525 0 : EWRITE4(sc, EAP_ICSC, 0);
526 0 : EWRITE4(sc, E1371_LEGACY, 0);
527 :
528 0 : if (sc->sc_ct5880) {
529 0 : EWRITE4(sc, EAP_ICSS, EAP_CT5880_AC97_RESET);
530 : /* Let codec wake up */
531 0 : delay(20000);
532 0 : }
533 :
534 : /* Reset from es1371's perspective */
535 0 : EWRITE4(sc, EAP_ICSC, E1371_SYNC_RES);
536 0 : delay(20);
537 0 : EWRITE4(sc, EAP_ICSC, 0);
538 :
539 : /*
540 : * Must properly reprogram sample rate converter,
541 : * or it locks up.
542 : *
543 : * We don't know how to program it (no documentation),
544 : * and the linux/oss magic receipe doesn't work (breaks
545 : * full-duplex, by selecting different play and record
546 : * rates). On the other hand, the sample rate converter
547 : * can't be disabled (disabling it would disable DMA),
548 : * so we use these magic defaults that make it "resample"
549 : * 48kHz to 48kHz without breaking full-duplex.
550 : */
551 0 : EWRITE4(sc, E1371_SRC, E1371_SRC_DISABLE);
552 0 : for (i = 0; i < 0x80; i++)
553 0 : eap1371_src_write(sc, i, 0);
554 0 : eap1371_src_write(sc, ESRC_ADC + ESRC_TRUNC_N, ESRC_SET_N(16));
555 0 : eap1371_src_write(sc, ESRC_ADC + ESRC_IREGS, ESRC_SET_VFI(16));
556 0 : eap1371_src_write(sc, ESRC_ADC + ESRC_VFF, 0);
557 0 : eap1371_src_write(sc, ESRC_ADC_VOLL, ESRC_SET_ADC_VOL(16));
558 0 : eap1371_src_write(sc, ESRC_ADC_VOLR, ESRC_SET_ADC_VOL(16));
559 0 : eap1371_src_write(sc, ESRC_DAC1 + ESRC_TRUNC_N, ESRC_SET_N(16));
560 0 : eap1371_src_write(sc, ESRC_DAC1 + ESRC_IREGS, ESRC_SET_VFI(16));
561 0 : eap1371_src_write(sc, ESRC_DAC1 + ESRC_VFF, 0);
562 0 : eap1371_src_write(sc, ESRC_DAC1_VOLL, ESRC_SET_DAC_VOLI(1));
563 0 : eap1371_src_write(sc, ESRC_DAC1_VOLR, ESRC_SET_DAC_VOLI(1));
564 0 : eap1371_src_write(sc, ESRC_DAC2 + ESRC_IREGS, ESRC_SET_VFI(16));
565 0 : eap1371_src_write(sc, ESRC_DAC2 + ESRC_TRUNC_N, ESRC_SET_N(16));
566 0 : eap1371_src_write(sc, ESRC_DAC2 + ESRC_VFF, 0);
567 0 : eap1371_src_write(sc, ESRC_DAC2_VOLL, ESRC_SET_DAC_VOLI(1));
568 0 : eap1371_src_write(sc, ESRC_DAC2_VOLR, ESRC_SET_DAC_VOLI(1));
569 0 : EWRITE4(sc, E1371_SRC, 0);
570 :
571 : /* Reset codec */
572 :
573 : /* Interrupt enable */
574 0 : sc->host_if.arg = sc;
575 0 : sc->host_if.attach = eap1371_attach_codec;
576 0 : sc->host_if.read = eap1371_read_codec;
577 0 : sc->host_if.write = eap1371_write_codec;
578 0 : sc->host_if.reset = eap1371_reset_codec;
579 0 : sc->host_if.flags = eap_flags_codec;
580 0 : sc->flags = AC97_HOST_DONT_READ;
581 :
582 0 : if (ac97_attach(&sc->host_if) == 0) {
583 : /* Interrupt enable */
584 0 : EWRITE4(sc, EAP_SIC, EAP_P2_INTR_EN | EAP_R1_INTR_EN);
585 : } else
586 0 : return;
587 :
588 : eap_hw_if = &eap1371_hw_if;
589 : }
590 :
591 0 : audio_attach_mi(eap_hw_if, sc, &sc->sc_dev);
592 : #if NMIDI > 0
593 0 : sc->sc_mididev = midi_attach_mi(&eap_midi_hw_if, sc, &sc->sc_dev);
594 : #endif
595 0 : }
596 :
597 : void
598 0 : eap_resume(struct eap_softc *sc)
599 : {
600 : int i;
601 :
602 0 : if (!sc->sc_1371) {
603 : /* Enable interrupts and looping mode. */
604 : /* enable the parts we need */
605 0 : EWRITE4(sc, EAP_SIC, EAP_P2_INTR_EN | EAP_R1_INTR_EN);
606 0 : EWRITE4(sc, EAP_ICSC, EAP_CDC_EN);
607 :
608 : /* reset codec */
609 : /* normal operation */
610 : /* select codec clocks */
611 0 : eap1370_write_codec(sc, AK_RESET, AK_PD);
612 0 : eap1370_write_codec(sc, AK_RESET, AK_PD | AK_NRST);
613 0 : eap1370_write_codec(sc, AK_CS, 0x0);
614 :
615 0 : } else {
616 : /* clean slate */
617 :
618 0 : EWRITE4(sc, EAP_SIC, 0);
619 0 : EWRITE4(sc, EAP_ICSC, 0);
620 0 : EWRITE4(sc, E1371_LEGACY, 0);
621 :
622 0 : if (sc->sc_ct5880) {
623 0 : EWRITE4(sc, EAP_ICSS, EAP_CT5880_AC97_RESET);
624 : /* Let codec wake up */
625 0 : delay(20000);
626 0 : }
627 :
628 0 : ac97_resume(&sc->host_if, sc->codec_if);
629 :
630 0 : EWRITE4(sc, E1371_SRC, E1371_SRC_DISABLE);
631 0 : for (i = 0; i < 0x80; i++)
632 0 : eap1371_src_write(sc, i, 0);
633 0 : eap1371_src_write(sc, ESRC_ADC + ESRC_TRUNC_N, ESRC_SET_N(16));
634 0 : eap1371_src_write(sc, ESRC_ADC + ESRC_IREGS, ESRC_SET_VFI(16));
635 0 : eap1371_src_write(sc, ESRC_ADC + ESRC_VFF, 0);
636 0 : eap1371_src_write(sc, ESRC_ADC_VOLL, ESRC_SET_ADC_VOL(16));
637 0 : eap1371_src_write(sc, ESRC_ADC_VOLR, ESRC_SET_ADC_VOL(16));
638 0 : eap1371_src_write(sc, ESRC_DAC1 + ESRC_TRUNC_N, ESRC_SET_N(16));
639 0 : eap1371_src_write(sc, ESRC_DAC1 + ESRC_IREGS, ESRC_SET_VFI(16));
640 0 : eap1371_src_write(sc, ESRC_DAC1 + ESRC_VFF, 0);
641 0 : eap1371_src_write(sc, ESRC_DAC1_VOLL, ESRC_SET_DAC_VOLI(1));
642 0 : eap1371_src_write(sc, ESRC_DAC1_VOLR, ESRC_SET_DAC_VOLI(1));
643 0 : eap1371_src_write(sc, ESRC_DAC2 + ESRC_IREGS, ESRC_SET_VFI(16));
644 0 : eap1371_src_write(sc, ESRC_DAC2 + ESRC_TRUNC_N, ESRC_SET_N(16));
645 0 : eap1371_src_write(sc, ESRC_DAC2 + ESRC_VFF, 0);
646 0 : eap1371_src_write(sc, ESRC_DAC2_VOLL, ESRC_SET_DAC_VOLI(1));
647 0 : eap1371_src_write(sc, ESRC_DAC2_VOLR, ESRC_SET_DAC_VOLI(1));
648 0 : EWRITE4(sc, E1371_SRC, 0);
649 :
650 : /* Interrupt enable */
651 0 : EWRITE4(sc, EAP_SIC, EAP_P2_INTR_EN | EAP_R1_INTR_EN);
652 : }
653 0 : }
654 :
655 :
656 : int
657 0 : eap1371_attach_codec(void *sc_, struct ac97_codec_if *codec_if)
658 : {
659 0 : struct eap_softc *sc = sc_;
660 :
661 0 : sc->codec_if = codec_if;
662 0 : return (0);
663 : }
664 :
665 : void
666 0 : eap1371_reset_codec(void *sc_)
667 : {
668 0 : struct eap_softc *sc = sc_;
669 : u_int32_t icsc;
670 :
671 0 : mtx_enter(&audio_lock);
672 0 : icsc = EREAD4(sc, EAP_ICSC);
673 0 : EWRITE4(sc, EAP_ICSC, icsc | E1371_SYNC_RES);
674 0 : delay(20);
675 0 : EWRITE4(sc, EAP_ICSC, icsc & ~E1371_SYNC_RES);
676 0 : delay(1);
677 0 : mtx_leave(&audio_lock);
678 :
679 : return;
680 0 : }
681 :
682 : int
683 0 : eap_intr(void *p)
684 : {
685 0 : struct eap_softc *sc = p;
686 : u_int32_t intr, sic;
687 :
688 0 : mtx_enter(&audio_lock);
689 0 : intr = EREAD4(sc, EAP_ICSS);
690 0 : if (!(intr & EAP_INTR)) {
691 0 : mtx_leave(&audio_lock);
692 0 : return (0);
693 : }
694 0 : sic = EREAD4(sc, EAP_SIC);
695 : DPRINTFN(5, ("eap_intr: ICSS=0x%08x, SIC=0x%08x\n", intr, sic));
696 0 : if (intr & EAP_I_ADC) {
697 : #if 0
698 : /*
699 : * XXX This is a hack!
700 : * The EAP chip sometimes generates the recording interrupt
701 : * while it is still transferring the data. To make sure
702 : * it has all arrived we busy wait until the count is right.
703 : * The transfer we are waiting for is 8 longwords.
704 : */
705 : int s, nw, n;
706 :
707 : EWRITE4(sc, EAP_MEMPAGE, EAP_ADC_PAGE);
708 : s = EREAD4(sc, EAP_ADC_CSR);
709 : nw = ((s & 0xffff) + 1) >> 2; /* # of words in DMA */
710 : n = 0;
711 : while (((EREAD4(sc, EAP_ADC_SIZE) >> 16) + 8) % nw == 0) {
712 : delay(10);
713 : if (++n > 100) {
714 : printf("eapintr: dma fix timeout");
715 : break;
716 : }
717 : }
718 : /* Continue with normal interrupt handling. */
719 : #endif
720 0 : EWRITE4(sc, EAP_SIC, sic & ~EAP_R1_INTR_EN);
721 0 : EWRITE4(sc, EAP_SIC, sic | EAP_R1_INTR_EN);
722 0 : if (sc->sc_rintr)
723 0 : sc->sc_rintr(sc->sc_rarg);
724 : }
725 0 : if (intr & EAP_I_DAC2) {
726 0 : EWRITE4(sc, EAP_SIC, sic & ~EAP_P2_INTR_EN);
727 0 : EWRITE4(sc, EAP_SIC, sic | EAP_P2_INTR_EN);
728 0 : if (sc->sc_pintr)
729 0 : sc->sc_pintr(sc->sc_parg);
730 : }
731 : #if NMIDI > 0
732 0 : if (intr & EAP_I_UART) {
733 : u_int32_t data;
734 :
735 0 : if (EREAD1(sc, EAP_UART_STATUS) & EAP_US_RXINT) {
736 0 : while (EREAD1(sc, EAP_UART_STATUS) & EAP_US_RXRDY) {
737 0 : data = EREAD1(sc, EAP_UART_DATA);
738 0 : if (sc->sc_iintr)
739 0 : sc->sc_iintr(sc->sc_arg, data);
740 : }
741 : }
742 0 : if (EREAD1(sc, EAP_UART_STATUS) & EAP_US_TXINT) {
743 0 : sc->sc_uctrl &= ~EAP_UC_TXINTEN;
744 0 : EWRITE1(sc, EAP_UART_CONTROL, sc->sc_uctrl);
745 0 : if (sc->sc_ointr)
746 0 : sc->sc_ointr(sc->sc_arg);
747 : }
748 0 : }
749 : #endif
750 0 : mtx_leave(&audio_lock);
751 0 : return (1);
752 0 : }
753 :
754 : int
755 0 : eap_allocmem(struct eap_softc *sc, size_t size, size_t align, struct eap_dma *p)
756 : {
757 : int error;
758 :
759 0 : p->size = size;
760 0 : error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
761 : p->segs, nitems(p->segs),
762 : &p->nsegs, BUS_DMA_NOWAIT);
763 0 : if (error)
764 0 : return (error);
765 :
766 0 : error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
767 : &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
768 0 : if (error)
769 : goto free;
770 :
771 0 : error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
772 : 0, BUS_DMA_NOWAIT, &p->map);
773 0 : if (error)
774 : goto unmap;
775 :
776 0 : error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
777 : BUS_DMA_NOWAIT);
778 0 : if (error)
779 : goto destroy;
780 0 : return (0);
781 :
782 : destroy:
783 0 : bus_dmamap_destroy(sc->sc_dmatag, p->map);
784 : unmap:
785 0 : bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
786 : free:
787 0 : bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
788 0 : return (error);
789 0 : }
790 :
791 : int
792 0 : eap_freemem(struct eap_softc *sc, struct eap_dma *p)
793 : {
794 0 : bus_dmamap_unload(sc->sc_dmatag, p->map);
795 0 : bus_dmamap_destroy(sc->sc_dmatag, p->map);
796 0 : bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
797 0 : bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
798 0 : return (0);
799 : }
800 :
801 : int
802 0 : eap_open(void *addr, int flags)
803 : {
804 0 : return (0);
805 : }
806 :
807 : /*
808 : * Close function is called at splaudio().
809 : */
810 : void
811 0 : eap_close(void *addr)
812 : {
813 0 : struct eap_softc *sc = addr;
814 :
815 0 : eap_halt_output(sc);
816 0 : eap_halt_input(sc);
817 :
818 0 : sc->sc_pintr = 0;
819 0 : sc->sc_rintr = 0;
820 0 : }
821 :
822 : int
823 0 : eap_set_params(void *addr, int setmode, int usemode,
824 : struct audio_params *play, struct audio_params *rec)
825 : {
826 0 : struct eap_softc *sc = addr;
827 : struct audio_params *p;
828 : int mode;
829 : u_int32_t div;
830 :
831 : /*
832 : * The es1370 only has one clock, so make the sample rates match.
833 : */
834 0 : if (!sc->sc_1371) {
835 0 : if (play->sample_rate != rec->sample_rate &&
836 0 : usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
837 0 : if (setmode == AUMODE_PLAY) {
838 0 : rec->sample_rate = play->sample_rate;
839 0 : setmode |= AUMODE_RECORD;
840 0 : } else if (setmode == AUMODE_RECORD) {
841 0 : play->sample_rate = rec->sample_rate;
842 0 : setmode |= AUMODE_PLAY;
843 : } else
844 0 : return (EINVAL);
845 : }
846 : }
847 :
848 0 : for (mode = AUMODE_RECORD; mode != -1;
849 0 : mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
850 0 : if ((setmode & mode) == 0)
851 : continue;
852 :
853 0 : p = mode == AUMODE_PLAY ? play : rec;
854 :
855 0 : if (sc->sc_1371)
856 0 : p->sample_rate = 48000;
857 0 : if (p->sample_rate < 4000)
858 0 : p->sample_rate = 4000;
859 0 : if (p->sample_rate > 48000)
860 0 : p->sample_rate = 48000;
861 0 : if (p->precision > 16)
862 0 : p->precision = 16;
863 0 : if (p->channels > 2)
864 0 : p->channels = 2;
865 0 : switch (p->encoding) {
866 : case AUDIO_ENCODING_SLINEAR_LE:
867 0 : if (p->precision != 16)
868 0 : return EINVAL;
869 : break;
870 : case AUDIO_ENCODING_ULINEAR_LE:
871 : case AUDIO_ENCODING_ULINEAR_BE:
872 0 : if (p->precision != 8)
873 0 : return EINVAL;
874 : default:
875 0 : return (EINVAL);
876 : }
877 0 : p->bps = AUDIO_BPS(p->precision);
878 0 : p->msb = 1;
879 0 : }
880 :
881 0 : if (!sc->sc_1371) {
882 : /* Set the speed */
883 : DPRINTFN(2, ("eap_set_params: old ICSC = 0x%08x\n",
884 : EREAD4(sc, EAP_ICSC)));
885 0 : div = EREAD4(sc, EAP_ICSC) & ~EAP_PCLKBITS;
886 : /*
887 : * XXX
888 : * The -2 isn't documented, but seemed to make the wall
889 : * time match
890 : * what I expect. - mycroft
891 : */
892 0 : if (usemode == AUMODE_RECORD)
893 0 : div |= EAP_SET_PCLKDIV(EAP_XTAL_FREQ /
894 : rec->sample_rate - 2);
895 : else
896 0 : div |= EAP_SET_PCLKDIV(EAP_XTAL_FREQ /
897 : play->sample_rate - 2);
898 0 : div |= EAP_CCB_INTRM;
899 0 : EWRITE4(sc, EAP_ICSC, div);
900 : DPRINTFN(2, ("eap_set_params: set ICSC = 0x%08x\n", div));
901 0 : }
902 :
903 0 : return (0);
904 0 : }
905 :
906 : int
907 0 : eap_round_blocksize(void *addr, int blk)
908 : {
909 0 : return ((blk + 31) & -32); /* keep good alignment */
910 : }
911 :
912 : int
913 0 : eap_trigger_output(
914 : void *addr,
915 : void *start,
916 : void *end,
917 : int blksize,
918 : void (*intr)(void *),
919 : void *arg,
920 : struct audio_params *param)
921 : {
922 0 : struct eap_softc *sc = addr;
923 : struct eap_dma *p;
924 : u_int32_t icsc, sic;
925 : int sampshift;
926 :
927 : #ifdef DIAGNOSTIC
928 0 : if (sc->sc_prun)
929 0 : panic("eap_trigger_output: already running");
930 0 : sc->sc_prun = 1;
931 : #endif
932 :
933 : DPRINTFN(1, ("eap_trigger_output: sc=%p start=%p end=%p "
934 : "blksize=%d intr=%p(%p)\n", addr, start, end, blksize, intr, arg));
935 0 : sc->sc_pintr = intr;
936 0 : sc->sc_parg = arg;
937 0 : mtx_enter(&audio_lock);
938 0 : sic = EREAD4(sc, EAP_SIC);
939 0 : sic &= ~(EAP_P2_S_EB | EAP_P2_S_MB | EAP_INC_BITS);
940 0 : sic |= EAP_SET_P2_ST_INC(0) | EAP_SET_P2_END_INC(param->precision / 8);
941 : sampshift = 0;
942 0 : if (param->precision == 16) {
943 0 : sic |= EAP_P2_S_EB;
944 : sampshift++;
945 0 : }
946 0 : if (param->channels == 2) {
947 0 : sic |= EAP_P2_S_MB;
948 0 : sampshift++;
949 0 : }
950 0 : EWRITE4(sc, EAP_SIC, sic & ~EAP_P2_INTR_EN);
951 0 : EWRITE4(sc, EAP_SIC, sic | EAP_P2_INTR_EN);
952 :
953 0 : for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
954 : ;
955 0 : if (!p) {
956 0 : mtx_leave(&audio_lock);
957 0 : printf("eap_trigger_output: bad addr %p\n", start);
958 0 : return (EINVAL);
959 : }
960 :
961 : DPRINTF(("eap_trigger_output: DAC2_ADDR=0x%x, DAC2_SIZE=0x%x\n",
962 : (int)DMAADDR(p),
963 : (int)EAP_SET_SIZE(0, (((char *)end - (char *)start) >> 2) - 1)));
964 0 : EWRITE4(sc, EAP_MEMPAGE, EAP_DAC_PAGE);
965 0 : EWRITE4(sc, EAP_DAC2_ADDR, DMAADDR(p));
966 0 : EWRITE4(sc, EAP_DAC2_SIZE,
967 : EAP_SET_SIZE(0, (((char *)end - (char *)start) >> 2) - 1));
968 :
969 0 : EWRITE4(sc, EAP_DAC2_CSR, (blksize >> sampshift) - 1);
970 :
971 0 : if (sc->sc_1371)
972 0 : EWRITE4(sc, E1371_SRC, 0);
973 :
974 0 : icsc = EREAD4(sc, EAP_ICSC);
975 0 : EWRITE4(sc, EAP_ICSC, icsc | EAP_DAC2_EN);
976 :
977 : DPRINTFN(1, ("eap_trigger_output: set ICSC = 0x%08x\n", icsc));
978 0 : mtx_leave(&audio_lock);
979 0 : return (0);
980 0 : }
981 :
982 : int
983 0 : eap_trigger_input(
984 : void *addr,
985 : void *start,
986 : void *end,
987 : int blksize,
988 : void (*intr)(void *),
989 : void *arg,
990 : struct audio_params *param)
991 : {
992 0 : struct eap_softc *sc = addr;
993 : struct eap_dma *p;
994 : u_int32_t icsc, sic;
995 : int sampshift;
996 :
997 : #ifdef DIAGNOSTIC
998 0 : if (sc->sc_rrun)
999 0 : panic("eap_trigger_input: already running");
1000 0 : sc->sc_rrun = 1;
1001 : #endif
1002 :
1003 : DPRINTFN(1, ("eap_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
1004 : addr, start, end, blksize, intr, arg));
1005 0 : sc->sc_rintr = intr;
1006 0 : sc->sc_rarg = arg;
1007 0 : mtx_enter(&audio_lock);
1008 0 : sic = EREAD4(sc, EAP_SIC);
1009 0 : sic &= ~(EAP_R1_S_EB | EAP_R1_S_MB);
1010 : sampshift = 0;
1011 0 : if (param->precision == 16) {
1012 0 : sic |= EAP_R1_S_EB;
1013 : sampshift++;
1014 0 : }
1015 0 : if (param->channels == 2) {
1016 0 : sic |= EAP_R1_S_MB;
1017 0 : sampshift++;
1018 0 : }
1019 0 : EWRITE4(sc, EAP_SIC, sic & ~EAP_R1_INTR_EN);
1020 0 : EWRITE4(sc, EAP_SIC, sic | EAP_R1_INTR_EN);
1021 :
1022 0 : for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
1023 : ;
1024 0 : if (!p) {
1025 0 : mtx_leave(&audio_lock);
1026 0 : printf("eap_trigger_input: bad addr %p\n", start);
1027 0 : return (EINVAL);
1028 : }
1029 :
1030 : DPRINTF(("eap_trigger_input: ADC_ADDR=0x%x, ADC_SIZE=0x%x\n",
1031 : (int)DMAADDR(p),
1032 : (int)EAP_SET_SIZE(0, (((char *)end - (char *)start) >> 2) - 1)));
1033 0 : EWRITE4(sc, EAP_MEMPAGE, EAP_ADC_PAGE);
1034 0 : EWRITE4(sc, EAP_ADC_ADDR, DMAADDR(p));
1035 0 : EWRITE4(sc, EAP_ADC_SIZE,
1036 : EAP_SET_SIZE(0, (((char *)end - (char *)start) >> 2) - 1));
1037 :
1038 0 : EWRITE4(sc, EAP_ADC_CSR, (blksize >> sampshift) - 1);
1039 :
1040 0 : if (sc->sc_1371)
1041 0 : EWRITE4(sc, E1371_SRC, 0);
1042 :
1043 0 : icsc = EREAD4(sc, EAP_ICSC);
1044 0 : EWRITE4(sc, EAP_ICSC, icsc | EAP_ADC_EN);
1045 :
1046 : DPRINTFN(1, ("eap_trigger_input: set ICSC = 0x%08x\n", icsc));
1047 0 : mtx_leave(&audio_lock);
1048 0 : return (0);
1049 0 : }
1050 :
1051 : int
1052 0 : eap_halt_output(void *addr)
1053 : {
1054 0 : struct eap_softc *sc = addr;
1055 : u_int32_t icsc;
1056 :
1057 : DPRINTF(("eap: eap_halt_output\n"));
1058 0 : mtx_enter(&audio_lock);
1059 0 : icsc = EREAD4(sc, EAP_ICSC);
1060 0 : EWRITE4(sc, EAP_ICSC, icsc & ~EAP_DAC2_EN);
1061 : #ifdef DIAGNOSTIC
1062 0 : sc->sc_prun = 0;
1063 : #endif
1064 0 : mtx_leave(&audio_lock);
1065 0 : return (0);
1066 : }
1067 :
1068 : int
1069 0 : eap_halt_input(void *addr)
1070 : {
1071 0 : struct eap_softc *sc = addr;
1072 : u_int32_t icsc;
1073 :
1074 : DPRINTF(("eap: eap_halt_input\n"));
1075 0 : mtx_enter(&audio_lock);
1076 0 : icsc = EREAD4(sc, EAP_ICSC);
1077 0 : EWRITE4(sc, EAP_ICSC, icsc & ~EAP_ADC_EN);
1078 : #ifdef DIAGNOSTIC
1079 0 : sc->sc_rrun = 0;
1080 : #endif
1081 0 : mtx_leave(&audio_lock);
1082 0 : return (0);
1083 : }
1084 :
1085 : int
1086 0 : eap1371_mixer_set_port(void *addr, mixer_ctrl_t *cp)
1087 : {
1088 0 : struct eap_softc *sc = addr;
1089 :
1090 0 : return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
1091 : }
1092 :
1093 : int
1094 0 : eap1371_mixer_get_port(void *addr, mixer_ctrl_t *cp)
1095 : {
1096 0 : struct eap_softc *sc = addr;
1097 :
1098 0 : return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
1099 : }
1100 :
1101 : int
1102 0 : eap1371_query_devinfo(void *addr, mixer_devinfo_t *dip)
1103 : {
1104 0 : struct eap_softc *sc = addr;
1105 :
1106 0 : return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
1107 : }
1108 :
1109 : void
1110 0 : eap1370_set_mixer(struct eap_softc *sc, int a, int d)
1111 : {
1112 0 : eap1370_write_codec(sc, a, d);
1113 :
1114 0 : sc->sc_port[a] = d;
1115 : DPRINTFN(1, ("eap1370_mixer_set_port port 0x%02x = 0x%02x\n", a, d));
1116 0 : }
1117 :
1118 : int
1119 0 : eap1370_mixer_set_port(void *addr, mixer_ctrl_t *cp)
1120 : {
1121 0 : struct eap_softc *sc = addr;
1122 : int lval, rval, l, r, la, ra;
1123 : int l1, r1, l2, r2, m, o1, o2;
1124 :
1125 0 : if (cp->dev == EAP_RECORD_SOURCE) {
1126 0 : if (cp->type != AUDIO_MIXER_SET)
1127 0 : return (EINVAL);
1128 0 : m = sc->sc_record_source = cp->un.mask;
1129 : l1 = l2 = r1 = r2 = 0;
1130 0 : if (m & (1 << EAP_VOICE_VOL))
1131 0 : l2 |= AK_M_VOICE, r2 |= AK_M_VOICE;
1132 0 : if (m & (1 << EAP_FM_VOL))
1133 0 : l1 |= AK_M_FM_L, r1 |= AK_M_FM_R;
1134 0 : if (m & (1 << EAP_CD_VOL))
1135 0 : l1 |= AK_M_CD_L, r1 |= AK_M_CD_R;
1136 0 : if (m & (1 << EAP_LINE_VOL))
1137 0 : l1 |= AK_M_LINE_L, r1 |= AK_M_LINE_R;
1138 0 : if (m & (1 << EAP_AUX_VOL))
1139 0 : l2 |= AK_M2_AUX_L, r2 |= AK_M2_AUX_R;
1140 0 : if (m & (1 << EAP_MIC_VOL))
1141 0 : l2 |= AK_M_TMIC, r2 |= AK_M_TMIC;
1142 0 : eap1370_set_mixer(sc, AK_IN_MIXER1_L, l1);
1143 0 : eap1370_set_mixer(sc, AK_IN_MIXER1_R, r1);
1144 0 : eap1370_set_mixer(sc, AK_IN_MIXER2_L, l2);
1145 0 : eap1370_set_mixer(sc, AK_IN_MIXER2_R, r2);
1146 0 : return (0);
1147 : }
1148 0 : if (cp->dev == EAP_INPUT_SOURCE) {
1149 0 : if (cp->type != AUDIO_MIXER_SET)
1150 0 : return (EINVAL);
1151 0 : m = sc->sc_input_source = cp->un.mask;
1152 : o1 = o2 = 0;
1153 0 : if (m & (1 << EAP_VOICE_VOL))
1154 0 : o2 |= AK_M_VOICE_L | AK_M_VOICE_R;
1155 0 : if (m & (1 << EAP_FM_VOL))
1156 0 : o1 |= AK_M_FM_L | AK_M_FM_R;
1157 0 : if (m & (1 << EAP_CD_VOL))
1158 0 : o1 |= AK_M_CD_L | AK_M_CD_R;
1159 0 : if (m & (1 << EAP_LINE_VOL))
1160 0 : o1 |= AK_M_LINE_L | AK_M_LINE_R;
1161 0 : if (m & (1 << EAP_AUX_VOL))
1162 0 : o2 |= AK_M_AUX_L | AK_M_AUX_R;
1163 0 : if (m & (1 << EAP_MIC_VOL))
1164 0 : o1 |= AK_M_MIC;
1165 0 : eap1370_set_mixer(sc, AK_OUT_MIXER1, o1);
1166 0 : eap1370_set_mixer(sc, AK_OUT_MIXER2, o2);
1167 0 : return (0);
1168 : }
1169 0 : if (cp->dev == EAP_MIC_PREAMP) {
1170 0 : if (cp->type != AUDIO_MIXER_ENUM)
1171 0 : return (EINVAL);
1172 0 : if (cp->un.ord != 0 && cp->un.ord != 1)
1173 0 : return (EINVAL);
1174 0 : sc->sc_mic_preamp = cp->un.ord;
1175 0 : eap1370_set_mixer(sc, AK_MGAIN, cp->un.ord);
1176 0 : return (0);
1177 : }
1178 0 : if (cp->type != AUDIO_MIXER_VALUE)
1179 0 : return (EINVAL);
1180 0 : if (cp->un.value.num_channels == 1)
1181 0 : lval = rval = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1182 0 : else if (cp->un.value.num_channels == 2) {
1183 0 : lval = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1184 0 : rval = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1185 : } else
1186 0 : return (EINVAL);
1187 : ra = -1;
1188 0 : switch (cp->dev) {
1189 : case EAP_MASTER_VOL:
1190 0 : l = VOL_TO_ATT5(lval);
1191 0 : r = VOL_TO_ATT5(rval);
1192 : la = AK_MASTER_L;
1193 : ra = AK_MASTER_R;
1194 0 : break;
1195 : case EAP_MIC_VOL:
1196 0 : if (cp->un.value.num_channels != 1)
1197 0 : return (EINVAL);
1198 : la = AK_MIC;
1199 0 : goto lr;
1200 : case EAP_VOICE_VOL:
1201 : la = AK_VOICE_L;
1202 : ra = AK_VOICE_R;
1203 0 : goto lr;
1204 : case EAP_FM_VOL:
1205 : la = AK_FM_L;
1206 : ra = AK_FM_R;
1207 0 : goto lr;
1208 : case EAP_CD_VOL:
1209 : la = AK_CD_L;
1210 : ra = AK_CD_R;
1211 0 : goto lr;
1212 : case EAP_LINE_VOL:
1213 : la = AK_LINE_L;
1214 : ra = AK_LINE_R;
1215 0 : goto lr;
1216 : case EAP_AUX_VOL:
1217 : la = AK_AUX_L;
1218 0 : ra = AK_AUX_R;
1219 : lr:
1220 0 : l = VOL_TO_GAIN5(lval);
1221 0 : r = VOL_TO_GAIN5(rval);
1222 0 : break;
1223 : default:
1224 0 : return (EINVAL);
1225 : }
1226 0 : eap1370_set_mixer(sc, la, l);
1227 0 : if (ra >= 0) {
1228 0 : eap1370_set_mixer(sc, ra, r);
1229 0 : }
1230 0 : return (0);
1231 0 : }
1232 :
1233 : int
1234 0 : eap1370_mixer_get_port(void *addr, mixer_ctrl_t *cp)
1235 : {
1236 0 : struct eap_softc *sc = addr;
1237 : int la, ra, l, r;
1238 :
1239 0 : switch (cp->dev) {
1240 : case EAP_RECORD_SOURCE:
1241 0 : if (cp->type != AUDIO_MIXER_SET)
1242 0 : return (EINVAL);
1243 0 : cp->un.mask = sc->sc_record_source;
1244 0 : return (0);
1245 : case EAP_INPUT_SOURCE:
1246 0 : if (cp->type != AUDIO_MIXER_SET)
1247 0 : return (EINVAL);
1248 0 : cp->un.mask = sc->sc_input_source;
1249 0 : return (0);
1250 : case EAP_MIC_PREAMP:
1251 0 : if (cp->type != AUDIO_MIXER_ENUM)
1252 0 : return (EINVAL);
1253 0 : cp->un.ord = sc->sc_mic_preamp;
1254 0 : return (0);
1255 : case EAP_MASTER_VOL:
1256 0 : l = ATT5_TO_VOL(sc->sc_port[AK_MASTER_L]);
1257 0 : r = ATT5_TO_VOL(sc->sc_port[AK_MASTER_R]);
1258 0 : break;
1259 : case EAP_MIC_VOL:
1260 0 : if (cp->un.value.num_channels != 1)
1261 0 : return (EINVAL);
1262 : la = ra = AK_MIC;
1263 0 : goto lr;
1264 : case EAP_VOICE_VOL:
1265 : la = AK_VOICE_L;
1266 : ra = AK_VOICE_R;
1267 0 : goto lr;
1268 : case EAP_FM_VOL:
1269 : la = AK_FM_L;
1270 : ra = AK_FM_R;
1271 0 : goto lr;
1272 : case EAP_CD_VOL:
1273 : la = AK_CD_L;
1274 : ra = AK_CD_R;
1275 0 : goto lr;
1276 : case EAP_LINE_VOL:
1277 : la = AK_LINE_L;
1278 : ra = AK_LINE_R;
1279 0 : goto lr;
1280 : case EAP_AUX_VOL:
1281 : la = AK_AUX_L;
1282 0 : ra = AK_AUX_R;
1283 : lr:
1284 0 : l = GAIN5_TO_VOL(sc->sc_port[la]);
1285 0 : r = GAIN5_TO_VOL(sc->sc_port[ra]);
1286 0 : break;
1287 : default:
1288 0 : return (EINVAL);
1289 : }
1290 0 : if (cp->un.value.num_channels == 1)
1291 0 : cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = (l+r) / 2;
1292 0 : else if (cp->un.value.num_channels == 2) {
1293 0 : cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
1294 0 : cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
1295 : } else
1296 0 : return (EINVAL);
1297 0 : return (0);
1298 0 : }
1299 :
1300 : int
1301 0 : eap1370_query_devinfo(void *addr, mixer_devinfo_t *dip)
1302 : {
1303 0 : switch (dip->index) {
1304 : case EAP_MASTER_VOL:
1305 0 : dip->type = AUDIO_MIXER_VALUE;
1306 0 : dip->mixer_class = EAP_OUTPUT_CLASS;
1307 0 : dip->prev = dip->next = AUDIO_MIXER_LAST;
1308 0 : strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
1309 0 : dip->un.v.num_channels = 2;
1310 0 : strlcpy(dip->un.v.units.name, AudioNvolume,
1311 : sizeof dip->un.v.units.name);
1312 0 : return (0);
1313 : case EAP_VOICE_VOL:
1314 0 : dip->type = AUDIO_MIXER_VALUE;
1315 0 : dip->mixer_class = EAP_INPUT_CLASS;
1316 0 : dip->prev = AUDIO_MIXER_LAST;
1317 0 : dip->next = AUDIO_MIXER_LAST;
1318 0 : strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
1319 0 : dip->un.v.num_channels = 2;
1320 0 : strlcpy(dip->un.v.units.name, AudioNvolume,
1321 : sizeof dip->un.v.units.name);
1322 0 : return (0);
1323 : case EAP_FM_VOL:
1324 0 : dip->type = AUDIO_MIXER_VALUE;
1325 0 : dip->mixer_class = EAP_INPUT_CLASS;
1326 0 : dip->prev = AUDIO_MIXER_LAST;
1327 0 : dip->next = AUDIO_MIXER_LAST;
1328 0 : strlcpy(dip->label.name, AudioNfmsynth,
1329 : sizeof dip->label.name);
1330 0 : dip->un.v.num_channels = 2;
1331 0 : strlcpy(dip->un.v.units.name, AudioNvolume,
1332 : sizeof dip->un.v.units.name);
1333 0 : return (0);
1334 : case EAP_CD_VOL:
1335 0 : dip->type = AUDIO_MIXER_VALUE;
1336 0 : dip->mixer_class = EAP_INPUT_CLASS;
1337 0 : dip->prev = AUDIO_MIXER_LAST;
1338 0 : dip->next = AUDIO_MIXER_LAST;
1339 0 : strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
1340 0 : dip->un.v.num_channels = 2;
1341 0 : strlcpy(dip->un.v.units.name, AudioNvolume,
1342 : sizeof dip->un.v.units.name);
1343 0 : return (0);
1344 : case EAP_LINE_VOL:
1345 0 : dip->type = AUDIO_MIXER_VALUE;
1346 0 : dip->mixer_class = EAP_INPUT_CLASS;
1347 0 : dip->prev = AUDIO_MIXER_LAST;
1348 0 : dip->next = AUDIO_MIXER_LAST;
1349 0 : strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
1350 0 : dip->un.v.num_channels = 2;
1351 0 : strlcpy(dip->un.v.units.name, AudioNvolume,
1352 : sizeof dip->un.v.units.name);
1353 0 : return (0);
1354 : case EAP_AUX_VOL:
1355 0 : dip->type = AUDIO_MIXER_VALUE;
1356 0 : dip->mixer_class = EAP_INPUT_CLASS;
1357 0 : dip->prev = AUDIO_MIXER_LAST;
1358 0 : dip->next = AUDIO_MIXER_LAST;
1359 0 : strlcpy(dip->label.name, AudioNaux, sizeof dip->label.name);
1360 0 : dip->un.v.num_channels = 2;
1361 0 : strlcpy(dip->un.v.units.name, AudioNvolume,
1362 : sizeof dip->un.v.units.name);
1363 0 : return (0);
1364 : case EAP_MIC_VOL:
1365 0 : dip->type = AUDIO_MIXER_VALUE;
1366 0 : dip->mixer_class = EAP_INPUT_CLASS;
1367 0 : dip->prev = AUDIO_MIXER_LAST;
1368 0 : dip->next = EAP_MIC_PREAMP;
1369 0 : strlcpy(dip->label.name, AudioNmicrophone,
1370 : sizeof dip->label.name);
1371 0 : dip->un.v.num_channels = 1;
1372 0 : strlcpy(dip->un.v.units.name, AudioNvolume,
1373 : sizeof dip->un.v.units.name);
1374 0 : return (0);
1375 : case EAP_RECORD_SOURCE:
1376 0 : dip->mixer_class = EAP_RECORD_CLASS;
1377 0 : dip->prev = dip->next = AUDIO_MIXER_LAST;
1378 0 : strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
1379 0 : dip->type = AUDIO_MIXER_SET;
1380 0 : dip->un.s.num_mem = 6;
1381 0 : strlcpy(dip->un.s.member[0].label.name, AudioNmicrophone,
1382 : sizeof dip->un.s.member[0].label.name);
1383 0 : dip->un.s.member[0].mask = 1 << EAP_MIC_VOL;
1384 0 : strlcpy(dip->un.s.member[1].label.name, AudioNcd,
1385 : sizeof dip->un.s.member[1].label.name);
1386 0 : dip->un.s.member[1].mask = 1 << EAP_CD_VOL;
1387 0 : strlcpy(dip->un.s.member[2].label.name, AudioNline,
1388 : sizeof dip->un.s.member[2].label.name);
1389 0 : dip->un.s.member[2].mask = 1 << EAP_LINE_VOL;
1390 0 : strlcpy(dip->un.s.member[3].label.name, AudioNfmsynth,
1391 : sizeof dip->un.s.member[3].label.name);
1392 0 : dip->un.s.member[3].mask = 1 << EAP_FM_VOL;
1393 0 : strlcpy(dip->un.s.member[4].label.name, AudioNaux,
1394 : sizeof dip->un.s.member[4].label.name);
1395 0 : dip->un.s.member[4].mask = 1 << EAP_AUX_VOL;
1396 0 : strlcpy(dip->un.s.member[5].label.name, AudioNdac,
1397 : sizeof dip->un.s.member[5].label.name);
1398 0 : dip->un.s.member[5].mask = 1 << EAP_VOICE_VOL;
1399 0 : return (0);
1400 : case EAP_INPUT_SOURCE:
1401 0 : dip->mixer_class = EAP_INPUT_CLASS;
1402 0 : dip->prev = dip->next = AUDIO_MIXER_LAST;
1403 0 : strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
1404 0 : dip->type = AUDIO_MIXER_SET;
1405 0 : dip->un.s.num_mem = 6;
1406 0 : strlcpy(dip->un.s.member[0].label.name, AudioNmicrophone,
1407 : sizeof dip->un.s.member[0].label.name);
1408 0 : dip->un.s.member[0].mask = 1 << EAP_MIC_VOL;
1409 0 : strlcpy(dip->un.s.member[1].label.name, AudioNcd,
1410 : sizeof dip->un.s.member[1].label.name);
1411 0 : dip->un.s.member[1].mask = 1 << EAP_CD_VOL;
1412 0 : strlcpy(dip->un.s.member[2].label.name, AudioNline,
1413 : sizeof dip->un.s.member[2].label.name);
1414 0 : dip->un.s.member[2].mask = 1 << EAP_LINE_VOL;
1415 0 : strlcpy(dip->un.s.member[3].label.name, AudioNfmsynth,
1416 : sizeof dip->un.s.member[3].label.name);
1417 0 : dip->un.s.member[3].mask = 1 << EAP_FM_VOL;
1418 0 : strlcpy(dip->un.s.member[4].label.name, AudioNaux,
1419 : sizeof dip->un.s.member[4].label.name);
1420 0 : dip->un.s.member[4].mask = 1 << EAP_AUX_VOL;
1421 0 : strlcpy(dip->un.s.member[5].label.name, AudioNdac,
1422 : sizeof dip->un.s.member[5].label.name);
1423 0 : dip->un.s.member[5].mask = 1 << EAP_VOICE_VOL;
1424 0 : return (0);
1425 : case EAP_MIC_PREAMP:
1426 0 : dip->type = AUDIO_MIXER_ENUM;
1427 0 : dip->mixer_class = EAP_INPUT_CLASS;
1428 0 : dip->prev = EAP_MIC_VOL;
1429 0 : dip->next = AUDIO_MIXER_LAST;
1430 0 : strlcpy(dip->label.name, AudioNpreamp, sizeof dip->label.name);
1431 0 : dip->un.e.num_mem = 2;
1432 0 : strlcpy(dip->un.e.member[0].label.name, AudioNoff,
1433 : sizeof dip->un.e.member[0].label.name);
1434 0 : dip->un.e.member[0].ord = 0;
1435 0 : strlcpy(dip->un.e.member[1].label.name, AudioNon,
1436 : sizeof dip->un.e.member[1].label.name);
1437 0 : dip->un.e.member[1].ord = 1;
1438 0 : return (0);
1439 : case EAP_OUTPUT_CLASS:
1440 0 : dip->type = AUDIO_MIXER_CLASS;
1441 0 : dip->mixer_class = EAP_OUTPUT_CLASS;
1442 0 : dip->next = dip->prev = AUDIO_MIXER_LAST;
1443 0 : strlcpy(dip->label.name, AudioCoutputs,
1444 : sizeof dip->label.name);
1445 0 : return (0);
1446 : case EAP_RECORD_CLASS:
1447 0 : dip->type = AUDIO_MIXER_CLASS;
1448 0 : dip->mixer_class = EAP_RECORD_CLASS;
1449 0 : dip->next = dip->prev = AUDIO_MIXER_LAST;
1450 0 : strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
1451 0 : return (0);
1452 : case EAP_INPUT_CLASS:
1453 0 : dip->type = AUDIO_MIXER_CLASS;
1454 0 : dip->mixer_class = EAP_INPUT_CLASS;
1455 0 : dip->next = dip->prev = AUDIO_MIXER_LAST;
1456 0 : strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
1457 0 : return (0);
1458 : }
1459 0 : return (ENXIO);
1460 0 : }
1461 :
1462 : void *
1463 0 : eap_malloc(void *addr, int direction, size_t size, int pool, int flags)
1464 : {
1465 0 : struct eap_softc *sc = addr;
1466 : struct eap_dma *p;
1467 : int error;
1468 :
1469 0 : p = malloc(sizeof(*p), pool, flags);
1470 0 : if (!p)
1471 0 : return (0);
1472 0 : error = eap_allocmem(sc, size, 16, p);
1473 0 : if (error) {
1474 0 : free(p, pool, 0);
1475 0 : return (0);
1476 : }
1477 0 : p->next = sc->sc_dmas;
1478 0 : sc->sc_dmas = p;
1479 0 : return (KERNADDR(p));
1480 0 : }
1481 :
1482 : void
1483 0 : eap_free(void *addr, void *ptr, int pool)
1484 : {
1485 0 : struct eap_softc *sc = addr;
1486 : struct eap_dma **pp, *p;
1487 :
1488 0 : for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
1489 0 : if (KERNADDR(p) == ptr) {
1490 0 : eap_freemem(sc, p);
1491 0 : *pp = p->next;
1492 0 : free(p, pool, 0);
1493 0 : return;
1494 : }
1495 : }
1496 0 : }
1497 :
1498 : int
1499 0 : eap_get_props(void *addr)
1500 : {
1501 0 : return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
1502 : AUDIO_PROP_FULLDUPLEX);
1503 : }
1504 :
1505 : enum ac97_host_flags
1506 0 : eap_flags_codec(void *v)
1507 : {
1508 0 : struct eap_softc *sc = v;
1509 :
1510 0 : return (sc->flags);
1511 : }
1512 : #if NMIDI > 0
1513 : int
1514 0 : eap_midi_open(void *addr, int flags,
1515 : void (*iintr)(void *, int),
1516 : void (*ointr)(void *),
1517 : void *arg)
1518 : {
1519 0 : struct eap_softc *sc = addr;
1520 :
1521 0 : sc->sc_iintr = iintr;
1522 0 : sc->sc_ointr = ointr;
1523 0 : sc->sc_arg = arg;
1524 :
1525 0 : EWRITE4(sc, EAP_ICSC, EREAD4(sc, EAP_ICSC) | EAP_UART_EN);
1526 0 : sc->sc_uctrl = 0;
1527 0 : if (flags & FREAD)
1528 0 : sc->sc_uctrl |= EAP_UC_RXINTEN;
1529 0 : EWRITE1(sc, EAP_UART_CONTROL, sc->sc_uctrl);
1530 :
1531 0 : return (0);
1532 : }
1533 :
1534 : void
1535 0 : eap_midi_close(void *addr)
1536 : {
1537 0 : struct eap_softc *sc = addr;
1538 :
1539 0 : tsleep(sc, PWAIT, "eapclm", hz/10); /* give uart a chance to drain */
1540 0 : EWRITE1(sc, EAP_UART_CONTROL, 0);
1541 0 : EWRITE4(sc, EAP_ICSC, EREAD4(sc, EAP_ICSC) & ~EAP_UART_EN);
1542 :
1543 0 : sc->sc_iintr = 0;
1544 0 : sc->sc_ointr = 0;
1545 0 : }
1546 :
1547 : int
1548 0 : eap_midi_output(void *addr, int d)
1549 : {
1550 0 : struct eap_softc *sc = addr;
1551 :
1552 0 : if (!(EREAD1(sc, EAP_UART_STATUS) & EAP_US_TXRDY))
1553 0 : return 0;
1554 0 : EWRITE1(sc, EAP_UART_DATA, d);
1555 0 : sc->sc_uctrl |= EAP_UC_TXINTEN;
1556 0 : EWRITE1(sc, EAP_UART_CONTROL, sc->sc_uctrl);
1557 0 : return 1;
1558 0 : }
1559 :
1560 : void
1561 0 : eap_midi_getinfo(void *addr, struct midi_info *mi)
1562 : {
1563 0 : mi->name = "AudioPCI MIDI UART";
1564 0 : mi->props = MIDI_PROP_CAN_INPUT | MIDI_PROP_OUT_INTR;
1565 0 : }
1566 :
1567 : #endif
|