xref: /openbsd-src/sys/dev/pci/auvia.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: auvia.c,v 1.9 2001/06/12 15:40:30 niklas Exp $ */
2 /*	$NetBSD: auvia.c,v 1.7 2000/11/15 21:06:33 jdolecek Exp $	*/
3 
4 /*-
5  * Copyright (c) 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Tyler C. Sarna
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  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the NetBSD
22  *	Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*
41  * VIA Technologies VT82C686A Southbridge Audio Driver
42  *
43  * Documentation links:
44  *
45  * ftp://ftp.alsa-project.org/pub/manuals/via/686a.pdf
46  * ftp://ftp.alsa-project.org/pub/manuals/general/ac97r21.pdf
47  * ftp://ftp.alsa-project.org/pub/manuals/ad/AD1881_0.pdf (example AC'97 codec)
48  */
49 
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/malloc.h>
53 #include <sys/device.h>
54 #include <sys/audioio.h>
55 
56 #include <vm/vm.h>
57 
58 #include <dev/pci/pcidevs.h>
59 #include <dev/pci/pcivar.h>
60 
61 #include <dev/audio_if.h>
62 #include <dev/mulaw.h>
63 #include <dev/auconv.h>
64 
65 #include <dev/ic/ac97.h>
66 
67 #include <dev/pci/auviavar.h>
68 
69 struct auvia_dma {
70 	struct auvia_dma *next;
71 	caddr_t addr;
72 	size_t size;
73 	bus_dmamap_t map;
74 	bus_dma_segment_t seg;
75 };
76 
77 struct auvia_dma_op {
78 	u_int32_t ptr;
79 	u_int32_t flags;
80 #define AUVIA_DMAOP_EOL		0x80000000
81 #define AUVIA_DMAOP_FLAG	0x40000000
82 #define AUVIA_DMAOP_STOP	0x20000000
83 #define AUVIA_DMAOP_COUNT(x)	((x)&0x00FFFFFF)
84 };
85 
86 /* rev. H and later seem to support only fixed rate 44.1 kHz */
87 #define	AUVIA_FIXED_RATE	44100
88 
89 int	auvia_match(struct device *, void *, void *);
90 void	auvia_attach(struct device *, struct device *, void *);
91 int	auvia_open(void *, int);
92 void	auvia_close(void *);
93 int	auvia_query_encoding(void *addr, struct audio_encoding *fp);
94 int	auvia_set_params(void *, int, int, struct audio_params *,
95 	struct audio_params *);
96 int	auvia_round_blocksize(void *, int);
97 int	auvia_halt_output(void *);
98 int	auvia_halt_input(void *);
99 int	auvia_getdev(void *, struct audio_device *);
100 int	auvia_set_port(void *, mixer_ctrl_t *);
101 int	auvia_get_port(void *, mixer_ctrl_t *);
102 int	auvia_query_devinfo(void *, mixer_devinfo_t *);
103 void *	auvia_malloc(void *, int, size_t, int, int);
104 void	auvia_free(void *, void *, int);
105 size_t	auvia_round_buffersize(void *, int, size_t);
106 int	auvia_mappage(void *, void *, int, int);
107 int	auvia_get_props(void *);
108 int	auvia_build_dma_ops(struct auvia_softc *, struct auvia_softc_chan *,
109 	struct auvia_dma *, void *, void *, int);
110 int	auvia_trigger_output(void *, void *, void *, int, void (*)(void *),
111 	void *, struct audio_params *);
112 int	auvia_trigger_input(void *, void *, void *, int, void (*)(void *),
113 	void *, struct audio_params *);
114 
115 int	auvia_intr __P((void *));
116 
117 struct  cfdriver auvia_cd = {
118 	NULL, "auvia", DV_DULL
119 };
120 
121 struct cfattach auvia_ca = {
122 	sizeof (struct auvia_softc), auvia_match, auvia_attach
123 };
124 
125 #define AUVIA_PCICONF_JUNK	0x40
126 #define		AUVIA_PCICONF_ENABLES	 0x00FF0000	/* reg 42 mask */
127 #define		AUVIA_PCICONF_ACLINKENAB 0x00008000	/* ac link enab */
128 #define		AUVIA_PCICONF_ACNOTRST	 0x00004000	/* ~(ac reset) */
129 #define		AUVIA_PCICONF_ACSYNC	 0x00002000	/* ac sync */
130 #define		AUVIA_PCICONF_ACVSR	 0x00000800	/* var. samp. rate */
131 #define		AUVIA_PCICONF_ACSGD	 0x00000400	/* SGD enab */
132 #define		AUVIA_PCICONF_ACFM	 0x00000200	/* FM enab */
133 #define		AUVIA_PCICONF_ACSB	 0x00000100	/* SB enab */
134 
135 #define AUVIA_PLAY_STAT			0x00
136 #define AUVIA_RECORD_STAT		0x10
137 #define		AUVIA_RPSTAT_INTR		0x03
138 #define AUVIA_PLAY_CONTROL		0x01
139 #define AUVIA_RECORD_CONTROL		0x11
140 #define		AUVIA_RPCTRL_START		0x80
141 #define		AUVIA_RPCTRL_TERMINATE		0x40
142 #define AUVIA_PLAY_MODE			0x02
143 #define AUVIA_RECORD_MODE		0x12
144 #define		AUVIA_RPMODE_INTR_FLAG		0x01
145 #define		AUVIA_RPMODE_INTR_EOL		0x02
146 #define		AUVIA_RPMODE_STEREO		0x10
147 #define		AUVIA_RPMODE_16BIT		0x20
148 #define		AUVIA_RPMODE_AUTOSTART		0x80
149 #define	AUVIA_PLAY_DMAOPS_BASE		0x04
150 #define	AUVIA_RECORD_DMAOPS_BASE	0x14
151 
152 #define	AUVIA_CODEC_CTL			0x80
153 #define		AUVIA_CODEC_READ		0x00800000
154 #define		AUVIA_CODEC_BUSY		0x01000000
155 #define		AUVIA_CODEC_PRIVALID		0x02000000
156 #define		AUVIA_CODEC_INDEX(x)		((x)<<16)
157 
158 #define TIMEOUT	50
159 
160 struct audio_hw_if auvia_hw_if = {
161 	auvia_open,
162 	auvia_close,
163 	NULL, /* drain */
164 	auvia_query_encoding,
165 	auvia_set_params,
166 	auvia_round_blocksize,
167 	NULL, /* commit_settings */
168 	NULL, /* init_output */
169 	NULL, /* init_input */
170 	NULL, /* start_output */
171 	NULL, /* start_input */
172 	auvia_halt_output,
173 	auvia_halt_input,
174 	NULL, /* speaker_ctl */
175 	auvia_getdev,
176 	NULL, /* setfd */
177 	auvia_set_port,
178 	auvia_get_port,
179 	auvia_query_devinfo,
180 	NULL,
181 	auvia_free,
182 	NULL,
183 	auvia_mappage,
184 	auvia_get_props,
185 	auvia_trigger_output,
186 	auvia_trigger_input,
187 	auvia_malloc,
188 	auvia_round_buffersize,
189 };
190 
191 int	auvia_attach_codec(void *, struct ac97_codec_if *);
192 int	auvia_write_codec(void *, u_int8_t, u_int16_t);
193 int	auvia_read_codec(void *, u_int8_t, u_int16_t *);
194 void	auvia_reset_codec(void *);
195 int	auvia_waitready_codec(struct auvia_softc *sc);
196 int	auvia_waitvalid_codec(struct auvia_softc *sc);
197 
198 
199 int
200 auvia_match(struct device *parent, void *match, void *aux)
201 {
202 	struct pci_attach_args *pa = (struct pci_attach_args *) aux;
203 
204 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH)
205 		return 0;
206 	if (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_VIATECH_VT82C686A_AC97)
207 		return 0;
208 
209 	return 1;
210 }
211 
212 
213 void
214 auvia_attach(struct device *parent, struct device *self, void *aux)
215 {
216 	struct pci_attach_args *pa = aux;
217 	struct auvia_softc *sc = (struct auvia_softc *) self;
218 	const char *intrstr = NULL;
219 	struct mixer_ctrl ctl;
220 	pci_chipset_tag_t pc = pa->pa_pc;
221 	pcitag_t pt = pa->pa_tag;
222 	pci_intr_handle_t ih;
223 	pcireg_t pr;
224 	u_int16_t v;
225 	int r, i;
226 
227 	if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin, pa->pa_intrline,
228 			&ih)) {
229 		printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
230 		return;
231 	}
232 	intrstr = pci_intr_string(pc, ih);
233 
234 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, auvia_intr, sc,
235 	    sc->sc_dev.dv_xname);
236 	if (sc->sc_ih == NULL) {
237 		printf(": couldn't establish interrupt");
238 		if (intrstr != NULL)
239 			printf(" at %s", intrstr);
240 		printf("\n");
241 		return;
242 	}
243 
244 	sc->sc_dmat = pa->pa_dmat;
245 	sc->sc_pc = pc;
246 	sc->sc_pt = pt;
247 
248 	printf(": %s\n", intrstr);
249 
250 	if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
251 	    &sc->sc_ioh, &sc->sc_ioaddr, &sc->sc_iosize, 0)) {
252 		printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
253 		return;
254 	}
255 
256 	/* disable SBPro compat & others */
257 	pr = pci_conf_read(pc, pt, AUVIA_PCICONF_JUNK);
258 
259 	pr &= ~AUVIA_PCICONF_ENABLES; /* clear compat function enables */
260 	/* XXX what to do about MIDI, FM, joystick? */
261 
262 	pr |= (AUVIA_PCICONF_ACLINKENAB | AUVIA_PCICONF_ACNOTRST
263 		| AUVIA_PCICONF_ACVSR | AUVIA_PCICONF_ACSGD);
264 
265 	pr &= ~(AUVIA_PCICONF_ACFM | AUVIA_PCICONF_ACSB);
266 
267 	pci_conf_write(pc, pt, AUVIA_PCICONF_JUNK, pr);
268 
269 	sc->host_if.arg = sc;
270 	sc->host_if.attach = auvia_attach_codec;
271 	sc->host_if.read = auvia_read_codec;
272 	sc->host_if.write = auvia_write_codec;
273 	sc->host_if.reset = auvia_reset_codec;
274 
275 	if ((r = ac97_attach(&sc->host_if)) != 0) {
276 		printf("%s: can't attach codec (error 0x%X)\n",
277 			sc->sc_dev.dv_xname, r);
278 		return;
279 	}
280 
281 	/*
282 	 * Print a warning if the codec doesn't support hardware variable
283 	 * rate audio.
284 	 */
285 	if (auvia_read_codec(sc, AC97_REG_EXT_AUDIO_ID, &v)
286 		|| !(v & AC97_EXT_AUDIO_VRA)) {
287 		printf("%s: warning: codec doesn't support hardware AC'97 2.0 Variable Rate Audio\n",
288 			sc->sc_dev.dv_xname);
289 		sc->sc_fixed_rate = AUVIA_FIXED_RATE;
290 	} else {
291 		/* enable VRA */
292 		auvia_write_codec(sc, AC97_REG_EXT_AUDIO_CTRL,
293 			AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_VRM);
294 		sc->sc_fixed_rate = 0;
295 	}
296 
297 	/* disable mutes */
298 	for (i = 0; i < 4; i++) {
299 		static struct {
300 			char *class, *device;
301 		} d[] = {
302 			{ AudioCoutputs, AudioNmaster},
303 			{ AudioCinputs, AudioNdac},
304 			{ AudioCinputs, AudioNcd},
305 			{ AudioCrecord, AudioNvolume},
306 		};
307 
308 		ctl.type = AUDIO_MIXER_ENUM;
309 		ctl.un.ord = 0;
310 
311 		ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
312 			d[i].class, d[i].device, AudioNmute);
313 		auvia_set_port(sc, &ctl);
314 	}
315 
316 	/* set a reasonable default volume */
317 
318 	ctl.type = AUDIO_MIXER_VALUE;
319 	ctl.un.value.num_channels = 2;
320 	ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
321 	ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 199;
322 
323 	ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
324 		AudioCoutputs, AudioNmaster, NULL);
325 	auvia_set_port(sc, &ctl);
326 
327 	audio_attach_mi(&auvia_hw_if, sc, &sc->sc_dev);
328 }
329 
330 
331 int
332 auvia_attach_codec(void *addr, struct ac97_codec_if *cif)
333 {
334 	struct auvia_softc *sc = addr;
335 
336 	sc->codec_if = cif;
337 
338 	return 0;
339 }
340 
341 
342 void
343 auvia_reset_codec(void *addr)
344 {
345 #ifdef notyet /* XXX seems to make codec become unready... ??? */
346 	struct auvia_softc *sc = addr;
347 	pcireg_t r;
348 
349 	/* perform a codec cold reset */
350 
351 	r = pci_conf_read(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK);
352 
353 	r &= ~AUVIA_PCICONF_ACNOTRST;	/* enable RESET (active low) */
354 	pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
355 	delay(2);
356 
357 	r |= AUVIA_PCICONF_ACNOTRST;		/* disable RESET (inactive high) */
358 	pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
359 	delay(200);
360 
361 	auvia_waitready_codec(sc);
362 #endif
363 }
364 
365 
366 int
367 auvia_waitready_codec(struct auvia_softc *sc)
368 {
369 	int i;
370 
371 	/* poll until codec not busy */
372 	for (i = 0; (i < TIMEOUT) && (bus_space_read_4(sc->sc_iot, sc->sc_ioh,
373 		AUVIA_CODEC_CTL) & AUVIA_CODEC_BUSY); i++)
374 		delay(1);
375 	if (i >= TIMEOUT) {
376 		printf("%s: codec busy\n", sc->sc_dev.dv_xname);
377 		return 1;
378 	}
379 
380 	return 0;
381 }
382 
383 
384 int
385 auvia_waitvalid_codec(struct auvia_softc *sc)
386 {
387 	int i;
388 
389 	/* poll until codec valid */
390 	for (i = 0; (i < TIMEOUT) && !(bus_space_read_4(sc->sc_iot, sc->sc_ioh,
391 		AUVIA_CODEC_CTL) & AUVIA_CODEC_PRIVALID); i++)
392 			delay(1);
393 	if (i >= TIMEOUT) {
394 		printf("%s: codec invalid\n", sc->sc_dev.dv_xname);
395 		return 1;
396 	}
397 
398 	return 0;
399 }
400 
401 
402 int
403 auvia_write_codec(void *addr, u_int8_t reg, u_int16_t val)
404 {
405 	struct auvia_softc *sc = addr;
406 
407 	if (auvia_waitready_codec(sc))
408 		return 1;
409 
410 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
411 		AUVIA_CODEC_PRIVALID | AUVIA_CODEC_INDEX(reg) | val);
412 
413 	return 0;
414 }
415 
416 
417 int
418 auvia_read_codec(void *addr, u_int8_t reg, u_int16_t *val)
419 {
420 	struct auvia_softc *sc = addr;
421 
422 	if (auvia_waitready_codec(sc))
423 		return 1;
424 
425 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
426 		AUVIA_CODEC_PRIVALID | AUVIA_CODEC_READ | AUVIA_CODEC_INDEX(reg));
427 
428 	if (auvia_waitready_codec(sc))
429 		return 1;
430 
431 	if (auvia_waitvalid_codec(sc))
432 		return 1;
433 
434 	*val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL);
435 
436 	return 0;
437 }
438 
439 
440 int
441 auvia_open(void *addr, int flags)
442 {
443 	return 0;
444 }
445 
446 
447 void
448 auvia_close(void *addr)
449 {
450 	struct auvia_softc *sc = addr;
451 
452 	auvia_halt_output(sc);
453 	auvia_halt_input(sc);
454 
455 	sc->sc_play.sc_intr = NULL;
456 	sc->sc_record.sc_intr = NULL;
457 }
458 
459 
460 int
461 auvia_query_encoding(void *addr, struct audio_encoding *fp)
462 {
463 	switch (fp->index) {
464 	case 0:
465 		strcpy(fp->name, AudioEulinear);
466 		fp->encoding = AUDIO_ENCODING_ULINEAR;
467 		fp->precision = 8;
468 		fp->flags = 0;
469 		return (0);
470 	case 1:
471 		strcpy(fp->name, AudioEmulaw);
472 		fp->encoding = AUDIO_ENCODING_ULAW;
473 		fp->precision = 8;
474 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
475 		return (0);
476 	case 2:
477 		strcpy(fp->name, AudioEalaw);
478 		fp->encoding = AUDIO_ENCODING_ALAW;
479 		fp->precision = 8;
480 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
481 		return (0);
482 	case 3:
483 		strcpy(fp->name, AudioEslinear);
484 		fp->encoding = AUDIO_ENCODING_SLINEAR;
485 		fp->precision = 8;
486 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
487 		return (0);
488 	case 4:
489 		strcpy(fp->name, AudioEslinear_le);
490 		fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
491 		fp->precision = 16;
492 		fp->flags = 0;
493 		return (0);
494 	case 5:
495 		strcpy(fp->name, AudioEulinear_le);
496 		fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
497 		fp->precision = 16;
498 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
499 		return (0);
500 	case 6:
501 		strcpy(fp->name, AudioEslinear_be);
502 		fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
503 		fp->precision = 16;
504 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
505 		return (0);
506 	case 7:
507 		strcpy(fp->name, AudioEulinear_be);
508 		fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
509 		fp->precision = 16;
510 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
511 		return (0);
512 	default:
513 		return (EINVAL);
514 	}
515 }
516 
517 
518 int
519 auvia_set_params(void *addr, int setmode, int usemode,
520 	struct audio_params *play, struct audio_params *rec)
521 {
522 	struct auvia_softc *sc = addr;
523 	struct audio_params *p;
524 	u_int16_t regval;
525 	int reg, mode;
526 
527 	/* for mode in (RECORD, PLAY) */
528 	for (mode = AUMODE_RECORD; mode != -1;
529 	     mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
530 		if ((setmode & mode) == 0)
531 			continue;
532 
533 		p = mode == AUMODE_PLAY ? play : rec;
534 
535 		if (p->sample_rate < 4000 || p->sample_rate > 48000 ||
536 		    (p->precision != 8 && p->precision != 16) ||
537 		    (p->channels != 1 && p->channels != 2))
538 			return (EINVAL);
539 
540 		reg = mode == AUMODE_PLAY ?
541 			AC97_REG_FRONT_DAC_RATE : AC97_REG_PCM_ADC_RATE;
542 
543 		if (!sc->sc_fixed_rate) {
544 			auvia_write_codec(sc, reg, (u_int16_t) p->sample_rate);
545 			auvia_read_codec(sc, reg, &regval);
546 			p->sample_rate = regval;
547 		} else
548 			p->sample_rate = sc->sc_fixed_rate;
549 
550 		p->factor = 1;
551 		p->sw_code = 0;
552 		switch (p->encoding) {
553 		case AUDIO_ENCODING_SLINEAR_BE:
554 			if (p->precision == 16)
555 				p->sw_code = swap_bytes;
556 			else
557 				p->sw_code = change_sign8;
558 			break;
559 		case AUDIO_ENCODING_SLINEAR_LE:
560 			if (p->precision != 16)
561 				p->sw_code = change_sign8;
562 			break;
563 		case AUDIO_ENCODING_ULINEAR_BE:
564 			if (p->precision == 16) {
565 				if (mode == AUMODE_PLAY)
566 					p->sw_code = swap_bytes_change_sign16_le;
567 				else
568 					p->sw_code = change_sign16_swap_bytes_le;
569 			}
570 			break;
571 		case AUDIO_ENCODING_ULINEAR_LE:
572 			if (p->precision == 16)
573 				p->sw_code = change_sign16_le;
574 			break;
575 		case AUDIO_ENCODING_ULAW:
576 			if (mode == AUMODE_PLAY) {
577 				p->factor = 2;
578 				p->sw_code = mulaw_to_slinear16_le;
579 			} else
580 				p->sw_code = ulinear8_to_mulaw;
581 			break;
582 		case AUDIO_ENCODING_ALAW:
583 			if (mode == AUMODE_PLAY) {
584 				p->factor = 2;
585 				p->sw_code = alaw_to_slinear16_le;
586 			} else
587 				p->sw_code = ulinear8_to_alaw;
588 			break;
589 		default:
590 			return (EINVAL);
591 		}
592 
593 		regval = (p->channels == 2 ? AUVIA_RPMODE_STEREO : 0)
594 			| (p->precision * p->factor == 16 ?
595 				AUVIA_RPMODE_16BIT : 0)
596 			| AUVIA_RPMODE_INTR_FLAG | AUVIA_RPMODE_INTR_EOL
597 			| AUVIA_RPMODE_AUTOSTART;
598 
599 		if (mode == AUMODE_PLAY) {
600 			sc->sc_play.sc_reg = regval;
601 		} else {
602 			sc->sc_record.sc_reg = regval;
603 		}
604 	}
605 
606 	return 0;
607 }
608 
609 
610 int
611 auvia_round_blocksize(void *addr, int blk)
612 {
613 	return (blk & -32);
614 }
615 
616 
617 int
618 auvia_halt_output(void *addr)
619 {
620 	struct auvia_softc *sc = addr;
621 
622 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_CONTROL,
623 		AUVIA_RPCTRL_TERMINATE);
624 
625 	return 0;
626 }
627 
628 
629 int
630 auvia_halt_input(void *addr)
631 {
632 	struct auvia_softc *sc = addr;
633 
634 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_CONTROL,
635 		AUVIA_RPCTRL_TERMINATE);
636 
637 	return 0;
638 }
639 
640 
641 int
642 auvia_getdev(void *addr, struct audio_device *retp)
643 {
644 	struct auvia_softc *sc = addr;
645 
646 	if (retp) {
647 		strncpy(retp->name, "VIA VT82C686A", sizeof(retp->name));
648 		strncpy(retp->version, sc->sc_revision, sizeof(retp->version));
649 		strncpy(retp->config, "auvia", sizeof(retp->config));
650 	}
651 
652 	return 0;
653 }
654 
655 
656 int
657 auvia_set_port(void *addr, mixer_ctrl_t *cp)
658 {
659 	struct auvia_softc *sc = addr;
660 
661 	return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
662 }
663 
664 
665 int
666 auvia_get_port(void *addr, mixer_ctrl_t *cp)
667 {
668 	struct auvia_softc *sc = addr;
669 
670 	return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
671 }
672 
673 
674 int
675 auvia_query_devinfo(void *addr, mixer_devinfo_t *dip)
676 {
677 	struct auvia_softc *sc = addr;
678 
679 	return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
680 }
681 
682 
683 void *
684 auvia_malloc(void *addr, int direction, size_t size, int pool, int flags)
685 {
686 	struct auvia_softc *sc = addr;
687 	struct auvia_dma *p;
688 	int error;
689 	int rseg;
690 
691 	p = malloc(sizeof(*p), pool, flags);
692 	if (!p)
693 		return 0;
694 
695 	p->size = size;
696 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg,
697 	    1, &rseg, BUS_DMA_NOWAIT)) != 0) {
698 		printf("%s: unable to allocate dma, error = %d\n",
699 		    sc->sc_dev.dv_xname, error);
700 		goto fail_alloc;
701 	}
702 
703 	if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
704 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
705 		printf("%s: unable to map dma, error = %d\n",
706 		    sc->sc_dev.dv_xname, error);
707 		goto fail_map;
708 	}
709 
710 	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
711 	    BUS_DMA_NOWAIT, &p->map)) != 0) {
712 		printf("%s: unable to create dma map, error = %d\n",
713 		    sc->sc_dev.dv_xname, error);
714 		goto fail_create;
715 	}
716 
717 	if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
718 	    BUS_DMA_NOWAIT)) != 0) {
719 		printf("%s: unable to load dma map, error = %d\n",
720 		    sc->sc_dev.dv_xname, error);
721 		goto fail_load;
722 	}
723 
724 	p->next = sc->sc_dmas;
725 	sc->sc_dmas = p;
726 
727 	return p->addr;
728 
729 
730 fail_load:
731 	bus_dmamap_destroy(sc->sc_dmat, p->map);
732 fail_create:
733 	bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
734 fail_map:
735 	bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
736 fail_alloc:
737 	free(p, pool);
738 	return 0;
739 }
740 
741 
742 void
743 auvia_free(void *addr, void *ptr, int pool)
744 {
745 	struct auvia_softc *sc = addr;
746 	struct auvia_dma **pp, *p;
747 
748 	for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
749 		if (p->addr == ptr) {
750 			bus_dmamap_unload(sc->sc_dmat, p->map);
751 			bus_dmamap_destroy(sc->sc_dmat, p->map);
752 			bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
753 			bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
754 
755 			*pp = p->next;
756 			free(p, pool);
757 			return;
758 		}
759 
760 	panic("auvia_free: trying to free unallocated memory");
761 }
762 
763 
764 size_t
765 auvia_round_buffersize(void *addr, int direction, size_t size)
766 {
767 	return size;
768 }
769 
770 
771 int
772 auvia_mappage(void *addr, void *mem, int off, int prot)
773 {
774 	struct auvia_softc *sc = addr;
775 	struct auvia_dma *p;
776 
777 	if (off < 0)
778 		return -1;
779 
780 	for (p = sc->sc_dmas; p && p->addr != mem; p = p->next)
781 		;
782 
783 	if (!p)
784 		return -1;
785 
786 	return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot,
787 	    BUS_DMA_WAITOK);
788 }
789 
790 
791 int
792 auvia_get_props(void *addr)
793 {
794 	return AUDIO_PROP_MMAP |  AUDIO_PROP_INDEPENDENT
795 		| AUDIO_PROP_FULLDUPLEX;
796 }
797 
798 
799 int
800 auvia_build_dma_ops(struct auvia_softc *sc, struct auvia_softc_chan *ch,
801 	struct auvia_dma *p, void *start, void *end, int blksize)
802 {
803 	struct auvia_dma_op *op;
804 	struct auvia_dma *dp;
805 	bus_addr_t s, e;
806 	size_t l;
807 	int segs;
808 
809 	s = p->map->dm_segs[0].ds_addr;
810 	l = ((char *)end - (char *)start);
811 	e = s + l;
812 	segs = (l + blksize - 1) / blksize;
813 
814 	if (segs > (ch->sc_dma_op_count)) {
815 		/* if old list was too small, free it */
816 		if (ch->sc_dma_ops) {
817 			auvia_free(sc, ch->sc_dma_ops, M_DEVBUF);
818 		}
819 
820 		ch->sc_dma_ops = auvia_malloc(sc, 0,
821 			sizeof(struct auvia_dma_op) * segs, M_DEVBUF, M_WAITOK);
822 
823 		for (dp = sc->sc_dmas;
824 			dp && dp->addr != (void *)(ch->sc_dma_ops);
825 			dp = dp->next)
826 				;
827 
828 		if (!dp)
829 			panic("%s: build_dma_ops: where'd my memory go??? "
830 				"address (%p)\n", sc->sc_dev.dv_xname,
831 				ch->sc_dma_ops);
832 
833 		ch->sc_dma_op_count = segs;
834 		ch->sc_dma_ops_dma = dp;
835 	}
836 
837 	dp = ch->sc_dma_ops_dma;
838 	op = ch->sc_dma_ops;
839 
840 	while (l) {
841 		op->ptr = s;
842 		l = l - blksize;
843 		if (!l) {
844 			/* if last block */
845 			op->flags = AUVIA_DMAOP_EOL | blksize;
846 		} else {
847 			op->flags = AUVIA_DMAOP_FLAG | blksize;
848 		}
849 		s += blksize;
850 		op++;
851 	}
852 
853 	return 0;
854 }
855 
856 
857 int
858 auvia_trigger_output(void *addr, void *start, void *end,
859 	int blksize, void (*intr)(void *), void *arg,
860 	struct audio_params *param)
861 {
862 	struct auvia_softc *sc = addr;
863 	struct auvia_softc_chan *ch = &(sc->sc_play);
864 	struct auvia_dma *p;
865 
866 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
867 		;
868 
869 	if (!p)
870 		panic("auvia_trigger_output: request with bad start "
871 			"address (%p)\n", start);
872 
873 	if (auvia_build_dma_ops(sc, ch, p, start, end, blksize)) {
874 		return 1;
875 	}
876 
877 	ch->sc_intr = intr;
878 	ch->sc_arg = arg;
879 
880 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_DMAOPS_BASE,
881 		ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
882 
883 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_MODE,
884 		ch->sc_reg);
885 
886 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_CONTROL,
887 		AUVIA_RPCTRL_START);
888 
889 	return 0;
890 }
891 
892 
893 int
894 auvia_trigger_input(void *addr, void *start, void *end,
895 	int blksize, void (*intr)(void *), void *arg,
896 	struct audio_params *param)
897 {
898 	struct auvia_softc *sc = addr;
899 	struct auvia_softc_chan *ch = &(sc->sc_record);
900 	struct auvia_dma *p;
901 
902 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
903 		;
904 
905 	if (!p)
906 		panic("auvia_trigger_input: request with bad start "
907 			"address (%p)\n", start);
908 
909 	if (auvia_build_dma_ops(sc, ch, p, start, end, blksize)) {
910 		return 1;
911 	}
912 
913 	ch->sc_intr = intr;
914 	ch->sc_arg = arg;
915 
916 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_DMAOPS_BASE,
917 		ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
918 
919 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_MODE,
920 		ch->sc_reg);
921 
922 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_CONTROL,
923 		AUVIA_RPCTRL_START);
924 
925 	return 0;
926 }
927 
928 
929 int
930 auvia_intr(void *arg)
931 {
932 	struct auvia_softc *sc = arg;
933 	u_int8_t r;
934 	int i = 0;
935 
936 	r = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_STAT);
937 	if (r & AUVIA_RPSTAT_INTR) {
938 		if (sc->sc_record.sc_intr)
939 			sc->sc_record.sc_intr(sc->sc_record.sc_arg);
940 
941 		/* clear interrupts */
942 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_RECORD_STAT,
943 			AUVIA_RPSTAT_INTR);
944 
945 		i++;
946 	}
947 	r = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_STAT);
948 	if (r & AUVIA_RPSTAT_INTR) {
949 		if (sc->sc_play.sc_intr)
950 			sc->sc_play.sc_intr(sc->sc_play.sc_arg);
951 
952 		/* clear interrupts */
953 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, AUVIA_PLAY_STAT,
954 			AUVIA_RPSTAT_INTR);
955 
956 		i++;
957 	}
958 
959 	return (i? 1 : 0);
960 }
961