xref: /openbsd-src/sys/dev/pci/auvia.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: auvia.c,v 1.57 2016/09/19 06:46:44 ratchov Exp $ */
2 /*	$NetBSD: auvia.c,v 1.28 2002/11/04 16:38:49 kent 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  *
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  * VIA Technologies VT82C686A Southbridge Audio Driver
35  *
36  * Documentation links:
37  *
38  * ftp://ftp.alsa-project.org/pub/manuals/via/686a.pdf
39  */
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
44 #include <sys/device.h>
45 #include <sys/audioio.h>
46 
47 #include <dev/pci/pcidevs.h>
48 #include <dev/pci/pcivar.h>
49 
50 #include <dev/audio_if.h>
51 
52 #include <dev/ic/ac97.h>
53 
54 #include <dev/pci/auviavar.h>
55 
56 struct auvia_dma {
57 	struct auvia_dma *next;
58 	caddr_t addr;
59 	size_t size;
60 	bus_dmamap_t map;
61 	bus_dma_segment_t seg;
62 };
63 
64 struct auvia_dma_op {
65 	u_int32_t ptr;
66 	u_int32_t flags;
67 #define AUVIA_DMAOP_EOL		0x80000000
68 #define AUVIA_DMAOP_FLAG	0x40000000
69 #define AUVIA_DMAOP_STOP	0x20000000
70 #define AUVIA_DMAOP_COUNT(x)	((x)&0x00FFFFFF)
71 };
72 
73 int	auvia_match(struct device *, void *, void *);
74 void	auvia_attach(struct device *, struct device *, void *);
75 int	auvia_open(void *, int);
76 void	auvia_close(void *);
77 void	auvia_set_params_sub(struct auvia_softc *, struct auvia_softc_chan *,
78 	struct audio_params *);
79 int	auvia_set_params(void *, int, int, struct audio_params *,
80 	struct audio_params *);
81 int	auvia_round_blocksize(void *, int);
82 int	auvia_halt_output(void *);
83 int	auvia_halt_input(void *);
84 int	auvia_set_port(void *, mixer_ctrl_t *);
85 int	auvia_get_port(void *, mixer_ctrl_t *);
86 int	auvia_query_devinfo(void *, mixer_devinfo_t *);
87 void *	auvia_malloc(void *, int, size_t, int, int);
88 void	auvia_free(void *, void *, int);
89 size_t	auvia_round_buffersize(void *, int, size_t);
90 int	auvia_get_props(void *);
91 int	auvia_build_dma_ops(struct auvia_softc *, struct auvia_softc_chan *,
92 	struct auvia_dma *, void *, void *, int);
93 int	auvia_trigger_output(void *, void *, void *, int, void (*)(void *),
94 	void *, struct audio_params *);
95 int	auvia_trigger_input(void *, void *, void *, int, void (*)(void *),
96 	void *, struct audio_params *);
97 
98 int	auvia_intr(void *);
99 
100 int	auvia_activate(struct device *, int);
101 
102 struct  cfdriver auvia_cd = {
103 	NULL, "auvia", DV_DULL
104 };
105 
106 struct cfattach auvia_ca = {
107 	sizeof (struct auvia_softc), auvia_match, auvia_attach,
108 	    NULL, auvia_activate
109 };
110 
111 #define AUVIA_PCICONF_JUNK	0x40
112 #define		AUVIA_PCICONF_ENABLES	 0x00FF0000	/* reg 42 mask */
113 #define		AUVIA_PCICONF_ACLINKENAB 0x00008000	/* ac link enab */
114 #define		AUVIA_PCICONF_ACNOTRST	 0x00004000	/* ~(ac reset) */
115 #define		AUVIA_PCICONF_ACSYNC	 0x00002000	/* ac sync */
116 #define		AUVIA_PCICONF_ACVSR	 0x00000800	/* var. samp. rate */
117 #define		AUVIA_PCICONF_ACSGD	 0x00000400	/* SGD enab */
118 #define		AUVIA_PCICONF_ACFM	 0x00000200	/* FM enab */
119 #define		AUVIA_PCICONF_ACSB	 0x00000100	/* SB enab */
120 #define		AUVIA_PCICONF_PRIVALID	 0x00000001	/* primary codec rdy */
121 
122 #define AUVIA_PLAY_BASE			0x00
123 #define AUVIA_RECORD_BASE		0x10
124 
125 /* *_RP_* are offsets from AUVIA_PLAY_BASE or AUVIA_RECORD_BASE */
126 #define	AUVIA_RP_STAT			0x00
127 #define		AUVIA_RPSTAT_INTR		0x03
128 #define AUVIA_RP_CONTROL		0x01
129 #define		AUVIA_RPCTRL_START		0x80
130 #define		AUVIA_RPCTRL_TERMINATE		0x40
131 #define		AUVIA_RPCTRL_AUTOSTART		0x20
132 /* The following are 8233 specific */
133 #define		AUVIA_RPCTRL_STOP		0x04
134 #define		AUVIA_RPCTRL_EOL		0x02
135 #define		AUVIA_RPCTRL_FLAG		0x01
136 #define	AUVIA_RP_MODE			0x02		/* 82c686 specific */
137 #define		AUVIA_RPMODE_INTR_FLAG		0x01
138 #define		AUVIA_RPMODE_INTR_EOL		0x02
139 #define		AUVIA_RPMODE_STEREO		0x10
140 #define		AUVIA_RPMODE_16BIT		0x20
141 #define		AUVIA_RPMODE_AUTOSTART		0x80
142 #define	AUVIA_RP_DMAOPS_BASE		0x04
143 
144 #define	VIA8233_RP_DXS_LVOL		0x02
145 #define	VIA8233_RP_DXS_RVOL		0x03
146 #define	VIA8233_RP_RATEFMT		0x08
147 #define		VIA8233_RATEFMT_48K	0xfffff
148 #define		VIA8233_RATEFMT_STEREO	0x00100000
149 #define		VIA8233_RATEFMT_16BIT	0x00200000
150 
151 #define VIA_RP_DMAOPS_COUNT		0x0c
152 
153 #define VIA8233_MP_BASE			0x40
154 	/* STAT, CONTROL, DMAOPS_BASE, DMAOPS_COUNT are valid */
155 #define VIA8233_OFF_MP_FORMAT		0x02
156 #define		VIA8233_MP_FORMAT_8BIT		0x00
157 #define		VIA8233_MP_FORMAT_16BIT		0x80
158 #define		VIA8233_MP_FORMAT_CHANNLE_MASK	0x70 /* 1, 2, 4, 6 */
159 #define VIA8233_OFF_MP_SCRATCH		0x03
160 #define VIA8233_OFF_MP_STOP		0x08
161 
162 #define VIA8233_WR_BASE			0x60
163 
164 #define	AUVIA_CODEC_CTL			0x80
165 #define		AUVIA_CODEC_READ		0x00800000
166 #define		AUVIA_CODEC_BUSY		0x01000000
167 #define		AUVIA_CODEC_PRIVALID		0x02000000
168 #define		AUVIA_CODEC_INDEX(x)		((x)<<16)
169 
170 #define CH_WRITE1(sc, ch, off, v)	\
171 	bus_space_write_1((sc)->sc_iot,	(sc)->sc_ioh, (ch)->sc_base + (off), v)
172 #define CH_WRITE4(sc, ch, off, v)	\
173 	bus_space_write_4((sc)->sc_iot,	(sc)->sc_ioh, (ch)->sc_base + (off), v)
174 #define CH_READ1(sc, ch, off)		\
175 	bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (ch)->sc_base + (off))
176 #define CH_READ4(sc, ch, off)		\
177 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (ch)->sc_base + (off))
178 
179 #define TIMEOUT	50
180 
181 struct audio_hw_if auvia_hw_if = {
182 	auvia_open,
183 	auvia_close,
184 	auvia_set_params,
185 	auvia_round_blocksize,
186 	NULL, /* commit_settings */
187 	NULL, /* init_output */
188 	NULL, /* init_input */
189 	NULL, /* start_output */
190 	NULL, /* start_input */
191 	auvia_halt_output,
192 	auvia_halt_input,
193 	NULL, /* speaker_ctl */
194 	NULL, /* setfd */
195 	auvia_set_port,
196 	auvia_get_port,
197 	auvia_query_devinfo,
198 	auvia_malloc,
199 	auvia_free,
200 	auvia_round_buffersize,
201 	auvia_get_props,
202 	auvia_trigger_output,
203 	auvia_trigger_input
204 };
205 
206 int	auvia_attach_codec(void *, struct ac97_codec_if *);
207 int	auvia_write_codec(void *, u_int8_t, u_int16_t);
208 int	auvia_read_codec(void *, u_int8_t, u_int16_t *);
209 void	auvia_reset_codec(void *);
210 int	auvia_waitready_codec(struct auvia_softc *sc);
211 int	auvia_waitvalid_codec(struct auvia_softc *sc);
212 void	auvia_spdif_event(void *, int);
213 
214 int	auvia_resume(struct auvia_softc *);
215 
216 const struct pci_matchid auvia_devices[] = {
217 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_AC97 },
218 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_AC97 },
219 };
220 
221 int
222 auvia_match(struct device *parent, void *match, void *aux)
223 {
224 	return (pci_matchbyid((struct pci_attach_args *)aux, auvia_devices,
225 	    nitems(auvia_devices)));
226 }
227 
228 int
229 auvia_activate(struct device *self, int act)
230 {
231 	struct auvia_softc *sc = (struct auvia_softc *)self;
232 	int rv = 0;
233 
234 	switch (act) {
235 	case DVACT_RESUME:
236 		auvia_resume(sc);
237 		rv = config_activate_children(self, act);
238 		break;
239 	default:
240 		rv = config_activate_children(self, act);
241 		break;
242 	}
243 	return (rv);
244 }
245 
246 
247 void
248 auvia_attach(struct device *parent, struct device *self, void *aux)
249 {
250 	struct pci_attach_args *pa = aux;
251 	struct auvia_softc *sc = (struct auvia_softc *) self;
252 	const char *intrstr = NULL;
253 	struct mixer_ctrl ctl;
254 	pci_chipset_tag_t pc = pa->pa_pc;
255 	pcitag_t pt = pa->pa_tag;
256 	pci_intr_handle_t ih;
257 	bus_size_t iosize;
258 	pcireg_t pr;
259 	int r, i;
260 
261 	sc->sc_play.sc_base = AUVIA_PLAY_BASE;
262 	sc->sc_record.sc_base = AUVIA_RECORD_BASE;
263 	if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT8233_AC97) {
264 		sc->sc_flags |= AUVIA_FLAGS_VT8233;
265 		sc->sc_play.sc_base = VIA8233_MP_BASE;
266 		sc->sc_record.sc_base = VIA8233_WR_BASE;
267 	}
268 
269 	if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
270 	    &sc->sc_ioh, NULL, &iosize, 0)) {
271 		printf(": can't map i/o space\n");
272 		return;
273 	}
274 
275 	sc->sc_dmat = pa->pa_dmat;
276 	sc->sc_pc = pc;
277 	sc->sc_pt = pt;
278 
279 	if (pci_intr_map(pa, &ih)) {
280 		printf(": couldn't map interrupt\n");
281 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
282 		return;
283 	}
284 	intrstr = pci_intr_string(pc, ih);
285 
286 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO | IPL_MPSAFE,
287 	    auvia_intr, sc, sc->sc_dev.dv_xname);
288 	if (sc->sc_ih == NULL) {
289 		printf(": couldn't establish interrupt");
290 		if (intrstr != NULL)
291 			printf(" at %s", intrstr);
292 		printf("\n");
293 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
294 		return;
295 	}
296 
297 	printf(": %s\n", intrstr);
298 
299 	/* disable SBPro compat & others */
300 	pr = pci_conf_read(pc, pt, AUVIA_PCICONF_JUNK);
301 
302 	pr &= ~AUVIA_PCICONF_ENABLES; /* clear compat function enables */
303 	/* XXX what to do about MIDI, FM, joystick? */
304 
305 	pr |= (AUVIA_PCICONF_ACLINKENAB | AUVIA_PCICONF_ACNOTRST |
306 	    AUVIA_PCICONF_ACVSR | AUVIA_PCICONF_ACSGD);
307 
308 	pr &= ~(AUVIA_PCICONF_ACFM | AUVIA_PCICONF_ACSB);
309 
310 	pci_conf_write(pc, pt, AUVIA_PCICONF_JUNK, pr);
311 	sc->sc_pci_junk = pr;
312 
313 	sc->host_if.arg = sc;
314 	sc->host_if.attach = auvia_attach_codec;
315 	sc->host_if.read = auvia_read_codec;
316 	sc->host_if.write = auvia_write_codec;
317 	sc->host_if.reset = auvia_reset_codec;
318 	sc->host_if.spdif_event = auvia_spdif_event;
319 
320 	if ((r = ac97_attach(&sc->host_if)) != 0) {
321 		printf("%s: can't attach codec (error 0x%X)\n",
322 		    sc->sc_dev.dv_xname, r);
323 		pci_intr_disestablish(pc, sc->sc_ih);
324 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
325 		return;
326 	}
327 
328 	/* disable mutes */
329 	for (i = 0; i < 4; i++) {
330 		static struct {
331 			char *class, *device;
332 		} d[] = {
333 			{ AudioCoutputs, AudioNmaster},
334 			{ AudioCinputs, AudioNdac},
335 			{ AudioCinputs, AudioNcd},
336 			{ AudioCrecord, AudioNvolume},
337 		};
338 
339 		ctl.type = AUDIO_MIXER_ENUM;
340 		ctl.un.ord = 0;
341 
342 		ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
343 		    d[i].class, d[i].device, AudioNmute);
344 		auvia_set_port(sc, &ctl);
345 	}
346 
347 	/* set a reasonable default volume */
348 
349 	ctl.type = AUDIO_MIXER_VALUE;
350 	ctl.un.value.num_channels = 2;
351 	ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
352 	ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 199;
353 
354 	ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
355 	    AudioCoutputs, AudioNmaster, NULL);
356 	auvia_set_port(sc, &ctl);
357 
358 	audio_attach_mi(&auvia_hw_if, sc, &sc->sc_dev);
359 	sc->codec_if->vtbl->unlock(sc->codec_if);
360 }
361 
362 
363 int
364 auvia_attach_codec(void *addr, struct ac97_codec_if *cif)
365 {
366 	struct auvia_softc *sc = addr;
367 
368 	sc->codec_if = cif;
369 
370 	return 0;
371 }
372 
373 
374 void
375 auvia_reset_codec(void *addr)
376 {
377 	int i;
378 	struct auvia_softc *sc = addr;
379 	pcireg_t r;
380 
381 	/* perform a codec cold reset */
382 
383 	r = pci_conf_read(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK);
384 
385 	r &= ~AUVIA_PCICONF_ACNOTRST;	/* enable RESET (active low) */
386 	pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
387 	delay(2);
388 
389 	r |= AUVIA_PCICONF_ACNOTRST;	/* disable RESET (inactive high) */
390 	pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
391 	delay(200);
392 
393 	for (i = 500000; i != 0 && !(pci_conf_read(sc->sc_pc, sc->sc_pt,
394 		AUVIA_PCICONF_JUNK) & AUVIA_PCICONF_PRIVALID); i--)
395 		DELAY(1);
396 	if (i == 0)
397 		printf("%s: codec reset timed out\n", sc->sc_dev.dv_xname);
398 }
399 
400 
401 int
402 auvia_waitready_codec(struct auvia_softc *sc)
403 {
404 	int i;
405 
406 	/* poll until codec not busy */
407 	for (i = 0; (i < TIMEOUT) && (bus_space_read_4(sc->sc_iot, sc->sc_ioh,
408 	     AUVIA_CODEC_CTL) & AUVIA_CODEC_BUSY); i++)
409 		delay(1);
410 
411 	if (i >= TIMEOUT) {
412 		printf("%s: codec busy\n", sc->sc_dev.dv_xname);
413 		return 1;
414 	}
415 
416 	return 0;
417 }
418 
419 
420 int
421 auvia_waitvalid_codec(struct auvia_softc *sc)
422 {
423 	int i;
424 
425 	/* poll until codec valid */
426 	for (i = 0; (i < TIMEOUT) && !(bus_space_read_4(sc->sc_iot, sc->sc_ioh,
427 	     AUVIA_CODEC_CTL) & AUVIA_CODEC_PRIVALID); i++)
428 		delay(1);
429 
430 	if (i >= TIMEOUT) {
431 		printf("%s: codec invalid\n", sc->sc_dev.dv_xname);
432 		return 1;
433 	}
434 
435 	return 0;
436 }
437 
438 
439 int
440 auvia_write_codec(void *addr, u_int8_t reg, u_int16_t val)
441 {
442 	struct auvia_softc *sc = addr;
443 
444 	if (auvia_waitready_codec(sc))
445 		return 1;
446 
447 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
448 	    AUVIA_CODEC_PRIVALID | AUVIA_CODEC_INDEX(reg) | val);
449 
450 	return 0;
451 }
452 
453 
454 int
455 auvia_read_codec(void *addr, u_int8_t reg, u_int16_t *val)
456 {
457 	struct auvia_softc *sc = addr;
458 
459 	if (auvia_waitready_codec(sc))
460 		return 1;
461 
462 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
463 	    AUVIA_CODEC_PRIVALID | AUVIA_CODEC_READ | AUVIA_CODEC_INDEX(reg));
464 
465 	if (auvia_waitready_codec(sc))
466 		return 1;
467 
468 	if (auvia_waitvalid_codec(sc))
469 		return 1;
470 
471 	*val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL);
472 
473 	return 0;
474 }
475 
476 
477 void
478 auvia_spdif_event(void *addr, int flag)
479 {
480 	struct auvia_softc *sc = addr;
481 	sc->sc_spdif = flag;
482 }
483 
484 int
485 auvia_open(void *addr, int flags)
486 {
487 	struct auvia_softc *sc = addr;
488 	sc->codec_if->vtbl->lock(sc->codec_if);
489 	return 0;
490 }
491 
492 
493 void
494 auvia_close(void *addr)
495 {
496 	struct auvia_softc *sc = addr;
497 	sc->codec_if->vtbl->unlock(sc->codec_if);
498 
499 	/* XXX: already called by audio_close() */
500 	auvia_halt_output(sc);
501 	auvia_halt_input(sc);
502 
503 	sc->sc_play.sc_intr = NULL;
504 	sc->sc_record.sc_intr = NULL;
505 }
506 
507 
508 void
509 auvia_set_params_sub(struct auvia_softc *sc, struct auvia_softc_chan *ch,
510 		     struct audio_params *p)
511 {
512 	u_int32_t v;
513 	u_int16_t regval;
514 
515 	if (!(sc->sc_flags & AUVIA_FLAGS_VT8233)) {
516 		regval = (p->channels == 2 ? AUVIA_RPMODE_STEREO : 0)
517 			| (p->precision == 16 ?
518 				AUVIA_RPMODE_16BIT : 0)
519 			| AUVIA_RPMODE_INTR_FLAG | AUVIA_RPMODE_INTR_EOL
520 			| AUVIA_RPMODE_AUTOSTART;
521 		ch->sc_reg = regval;
522 	} else if (ch->sc_base != VIA8233_MP_BASE) {
523 		v = CH_READ4(sc, ch, VIA8233_RP_RATEFMT);
524 		v &= ~(VIA8233_RATEFMT_48K | VIA8233_RATEFMT_STEREO
525 			| VIA8233_RATEFMT_16BIT);
526 
527 		v |= VIA8233_RATEFMT_48K * (p->sample_rate / 20)
528 			/ (48000 / 20);
529 		if (p->channels == 2)
530 			v |= VIA8233_RATEFMT_STEREO;
531 		if (p->precision == 16)
532 			v |= VIA8233_RATEFMT_16BIT;
533 
534 		CH_WRITE4(sc, ch, VIA8233_RP_RATEFMT, v);
535 	} else {
536 		static const u_int32_t slottab[7] =
537 			{ 0, 0xff000011, 0xff000021, 0,
538 			  0xff004321, 0, 0xff436521};
539 
540 		regval = (p->precision == 16
541 			? VIA8233_MP_FORMAT_16BIT : VIA8233_MP_FORMAT_8BIT)
542 			| (p->channels << 4);
543 		CH_WRITE1(sc, ch, VIA8233_OFF_MP_FORMAT, regval);
544 		CH_WRITE4(sc, ch, VIA8233_OFF_MP_STOP, slottab[p->channels]);
545 	}
546 }
547 
548 int
549 auvia_set_params(void *addr, int setmode, int usemode,
550     struct audio_params *play, struct audio_params *rec)
551 {
552 	struct auvia_softc *sc = addr;
553 	struct auvia_softc_chan *ch;
554 	struct audio_params *p;
555 	struct ac97_codec_if* codec = sc->codec_if;
556 	int reg, mode;
557 	u_int16_t ext_id;
558 
559 	/* for mode in (RECORD, PLAY) */
560 	for (mode = AUMODE_RECORD; mode != -1;
561 	     mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
562 		if ((setmode & mode) == 0)
563 			continue;
564 
565 		if (mode == AUMODE_PLAY) {
566 			p = play;
567 			ch = &sc->sc_play;
568 			reg = AC97_REG_PCM_FRONT_DAC_RATE;
569 		} else {
570 			p = rec;
571 			ch = &sc->sc_record;
572 			reg = AC97_REG_PCM_LR_ADC_RATE;
573 		}
574 
575 		if (ch->sc_base == VIA8233_MP_BASE && mode == AUMODE_PLAY) {
576 			ext_id = codec->vtbl->get_caps(codec);
577 			if (p->channels == 1) {
578 				/* ok */
579 			} else if (p->channels == 2) {
580 				/* ok */
581 			} else if (p->channels == 4
582 				&& ext_id & AC97_EXT_AUDIO_SDAC) {
583 				/* ok */
584 			} else if (p->channels == 6
585 				&& (ext_id & AC97_BITS_6CH) == AC97_BITS_6CH) {
586 				/* ok */
587 			} else {
588 				p->channels = 2;
589 			}
590 		} else {
591 			if (p->channels > 2)
592 				p->channels = 2;
593 		}
594 
595 		if (p->sample_rate < 4000)
596 			p->sample_rate = 4000;
597 		if (p->sample_rate > 48000)
598 			p->sample_rate = 48000;
599 		if (p->precision > 16)
600 			p->precision = 16;
601 
602 		/* XXX only 16-bit 48kHz slinear_le if s/pdif enabled ? */
603 		if (sc->sc_spdif) {
604 			p->sample_rate = 48000;
605 			p->precision = 16;
606 			p->encoding = AUDIO_ENCODING_SLINEAR_LE;
607 		}
608 
609 		/* XXX only 16-bit 48kHz slinear_le if s/pdif enabled ? */
610 		if (sc->sc_spdif &&
611 		    ((p->sample_rate != 48000) || (p->precision != 16) ||
612 		    (p->encoding != AUDIO_ENCODING_SLINEAR_LE)))
613 			return (EINVAL);
614 
615 		if (AC97_IS_FIXED_RATE(codec)) {
616  			p->sample_rate = AC97_SINGLE_RATE;
617  		} else {
618 			if (codec->vtbl->set_rate(codec, reg, &p->sample_rate))
619 				return (EINVAL);
620 
621 			if (ch->sc_base == VIA8233_MP_BASE &&
622 			    mode == AUMODE_PLAY) {
623 				reg = AC97_REG_PCM_SURR_DAC_RATE;
624 				if (p->channels >= 4
625 				    && codec->vtbl->set_rate(codec, reg,
626 				    &p->sample_rate))
627 					return (EINVAL);
628 				reg = AC97_REG_PCM_LFE_DAC_RATE;
629 				if (p->channels == 6
630 				    && codec->vtbl->set_rate(codec, reg,
631 				    &p->sample_rate))
632  				return (EINVAL);
633 			}
634  		}
635 
636 		switch (p->encoding) {
637 		case AUDIO_ENCODING_SLINEAR_LE:
638 			if (p->precision != 16)
639 				return EINVAL;
640 			break;
641 		case AUDIO_ENCODING_ULINEAR_LE:
642 		case AUDIO_ENCODING_ULINEAR_BE:
643 			if (p->precision != 8)
644 				return EINVAL;
645 			break;
646 		default:
647 			return (EINVAL);
648 		}
649 		auvia_set_params_sub(sc, ch, p);
650 
651 		p->bps = AUDIO_BPS(p->precision);
652 		p->msb = 1;
653 	}
654 
655 	return 0;
656 }
657 
658 
659 int
660 auvia_round_blocksize(void *addr, int blk)
661 {
662 	struct auvia_softc *sc = addr;
663 
664 	if (sc->bufsize / blk > AUVIA_DMALIST_MAX)
665 		blk = sc->bufsize / AUVIA_DMALIST_MAX + 1;
666 	return ((blk + 31) & -32);
667 }
668 
669 
670 int
671 auvia_halt_output(void *addr)
672 {
673 	struct auvia_softc *sc = addr;
674 	struct auvia_softc_chan *ch = &(sc->sc_play);
675 
676 	CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE);
677 	ch->sc_intr = NULL;
678 	return 0;
679 }
680 
681 
682 int
683 auvia_halt_input(void *addr)
684 {
685 	struct auvia_softc *sc = addr;
686 	struct auvia_softc_chan *ch = &(sc->sc_record);
687 
688 	CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE);
689 	ch->sc_intr = NULL;
690 	return 0;
691 }
692 
693 
694 int
695 auvia_set_port(void *addr, mixer_ctrl_t *cp)
696 {
697 	struct auvia_softc *sc = addr;
698 
699 	return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
700 }
701 
702 
703 int
704 auvia_get_port(void *addr, mixer_ctrl_t *cp)
705 {
706 	struct auvia_softc *sc = addr;
707 
708 	return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
709 }
710 
711 
712 int
713 auvia_query_devinfo(void *addr, mixer_devinfo_t *dip)
714 {
715 	struct auvia_softc *sc = addr;
716 
717 	return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
718 }
719 
720 
721 void *
722 auvia_malloc(void *addr, int direction, size_t size, int pool, int flags)
723 {
724 	struct auvia_softc *sc = addr;
725 	struct auvia_dma *p;
726 	int error;
727 	int rseg;
728 
729 	p = malloc(sizeof(*p), pool, flags);
730 	if (!p)
731 		return 0;
732 
733 	p->size = size;
734 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg,
735 	    1, &rseg, BUS_DMA_NOWAIT)) != 0) {
736 		printf("%s: unable to allocate dma, error = %d\n",
737 		    sc->sc_dev.dv_xname, error);
738 		goto fail_alloc;
739 	}
740 
741 	if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
742 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
743 		printf("%s: unable to map dma, error = %d\n",
744 		    sc->sc_dev.dv_xname, error);
745 		goto fail_map;
746 	}
747 
748 	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
749 	    BUS_DMA_NOWAIT, &p->map)) != 0) {
750 		printf("%s: unable to create dma map, error = %d\n",
751 		    sc->sc_dev.dv_xname, error);
752 		goto fail_create;
753 	}
754 
755 	if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
756 	    BUS_DMA_NOWAIT)) != 0) {
757 		printf("%s: unable to load dma map, error = %d\n",
758 		    sc->sc_dev.dv_xname, error);
759 		goto fail_load;
760 	}
761 
762 	p->next = sc->sc_dmas;
763 	sc->sc_dmas = p;
764 
765 	return p->addr;
766 
767 
768 fail_load:
769 	bus_dmamap_destroy(sc->sc_dmat, p->map);
770 fail_create:
771 	bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
772 fail_map:
773 	bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
774 fail_alloc:
775 	free(p, pool, 0);
776 	return 0;
777 }
778 
779 
780 void
781 auvia_free(void *addr, void *ptr, int pool)
782 {
783 	struct auvia_softc *sc = addr;
784 	struct auvia_dma **pp, *p;
785 
786 	for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
787 		if (p->addr == ptr) {
788 			bus_dmamap_unload(sc->sc_dmat, p->map);
789 			bus_dmamap_destroy(sc->sc_dmat, p->map);
790 			bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
791 			bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
792 
793 			*pp = p->next;
794 			free(p, pool, 0);
795 			return;
796 		}
797 
798 	panic("auvia_free: trying to free unallocated memory");
799 }
800 
801 size_t
802 auvia_round_buffersize(void *addr, int direction, size_t bufsize)
803 {
804 	struct auvia_softc *sc = addr;
805 
806 	sc->bufsize = bufsize;
807 	return bufsize;
808 }
809 
810 int
811 auvia_get_props(void *addr)
812 {
813 	int props;
814 
815 	props = AUDIO_PROP_MMAP|AUDIO_PROP_INDEPENDENT|AUDIO_PROP_FULLDUPLEX;
816 
817 	return  props;
818 }
819 
820 
821 int
822 auvia_build_dma_ops(struct auvia_softc *sc, struct auvia_softc_chan *ch,
823     struct auvia_dma *p, void *start, void *end, int blksize)
824 {
825 	struct auvia_dma_op *op;
826 	struct auvia_dma *dp;
827 	bus_addr_t s;
828 	size_t l;
829 	int segs;
830 
831 	s = p->map->dm_segs[0].ds_addr;
832 	l = (vaddr_t)end - (vaddr_t)start;
833 	segs = howmany(l, blksize);
834 	if (segs > AUVIA_DMALIST_MAX) {
835 		panic("%s: build_dma_ops: too many DMA segments",
836 			    sc->sc_dev.dv_xname);
837 	}
838 
839 	if (segs > ch->sc_dma_op_count) {
840 		/* if old list was too small, free it */
841 		if (ch->sc_dma_ops)
842 			auvia_free(sc, ch->sc_dma_ops, M_DEVBUF);
843 
844 		ch->sc_dma_ops = auvia_malloc(sc, 0,
845 		    sizeof(struct auvia_dma_op) * segs, M_DEVBUF, M_WAITOK);
846 
847 		for (dp = sc->sc_dmas; dp &&
848 		     dp->addr != (void *)(ch->sc_dma_ops); dp = dp->next)
849 			;
850 
851 		if (!dp)
852 			panic("%s: build_dma_ops: where'd my memory go??? "
853 			    "address (%p)", sc->sc_dev.dv_xname,
854 			    ch->sc_dma_ops);
855 
856 		ch->sc_dma_op_count = segs;
857 		ch->sc_dma_ops_dma = dp;
858 	}
859 
860 	op = ch->sc_dma_ops;
861 
862 	while (l) {
863 		op->ptr = htole32(s);
864 		l = l - min(l, blksize);
865 		/* if last block */
866 		op->flags = htole32((l? AUVIA_DMAOP_FLAG : AUVIA_DMAOP_EOL) | blksize);
867 		s += blksize;
868 		op++;
869 	}
870 
871 	return 0;
872 }
873 
874 
875 int
876 auvia_trigger_output(void *addr, void *start, void *end, int blksize,
877     void (*intr)(void *), void *arg, struct audio_params *param)
878 {
879 	struct auvia_softc *sc = addr;
880 	struct auvia_softc_chan *ch = &(sc->sc_play);
881 	struct auvia_dma *p;
882 
883 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
884 		;
885 
886 	if (!p)
887 		panic("auvia_trigger_output: request with bad start "
888 		    "address (%p)", start);
889 
890 	if (auvia_build_dma_ops(sc, ch, p, start, end, blksize)) {
891 		return 1;
892 	}
893 
894 	ch->sc_intr = intr;
895 	ch->sc_arg = arg;
896 
897 	CH_WRITE4(sc, ch, AUVIA_RP_DMAOPS_BASE,
898 	    ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
899 	mtx_enter(&audio_lock);
900 	if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
901 		if (ch->sc_base != VIA8233_MP_BASE) {
902 			CH_WRITE1(sc, ch, VIA8233_RP_DXS_LVOL, 0);
903 			CH_WRITE1(sc, ch, VIA8233_RP_DXS_RVOL, 0);
904 		}
905 		CH_WRITE1(sc, ch, AUVIA_RP_CONTROL,
906 		    AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART |
907 		    AUVIA_RPCTRL_STOP  | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
908 	} else {
909 		CH_WRITE1(sc, ch, AUVIA_RP_MODE, ch->sc_reg);
910 		CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_START);
911 	}
912 	mtx_leave(&audio_lock);
913 	return 0;
914 }
915 
916 
917 int
918 auvia_trigger_input(void *addr, void *start, void *end, int blksize,
919     void (*intr)(void *), void *arg, struct audio_params *param)
920 {
921 	struct auvia_softc *sc = addr;
922 	struct auvia_softc_chan *ch = &(sc->sc_record);
923 	struct auvia_dma *p;
924 
925 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
926 		;
927 
928 	if (!p)
929 		panic("auvia_trigger_input: request with bad start "
930 		    "address (%p)", start);
931 
932 	if (auvia_build_dma_ops(sc, ch, p, start, end, blksize))
933 		return 1;
934 
935 	ch->sc_intr = intr;
936 	ch->sc_arg = arg;
937 
938 	CH_WRITE4(sc, ch, AUVIA_RP_DMAOPS_BASE,
939 		  ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
940 
941 	mtx_enter(&audio_lock);
942 	if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
943 		if (ch->sc_base != VIA8233_MP_BASE) {
944 			CH_WRITE1(sc, ch, VIA8233_RP_DXS_LVOL, 0);
945 			CH_WRITE1(sc, ch, VIA8233_RP_DXS_RVOL, 0);
946 		}
947 		CH_WRITE1(sc, ch, AUVIA_RP_CONTROL,
948 		    AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART |
949 		    AUVIA_RPCTRL_STOP  | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
950 	} else {
951 		CH_WRITE1(sc, ch, AUVIA_RP_MODE, ch->sc_reg);
952 		CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_START);
953 	}
954 	mtx_leave(&audio_lock);
955 	return 0;
956 }
957 
958 
959 int
960 auvia_intr(void *arg)
961 {
962 	struct auvia_softc *sc = arg;
963 	struct auvia_softc_chan *ch;
964 	u_int8_t r;
965 	int i = 0;
966 
967 	mtx_enter(&audio_lock);
968 	ch = &sc->sc_record;
969 	r = CH_READ1(sc, ch, AUVIA_RP_STAT);
970 	if (r & AUVIA_RPSTAT_INTR) {
971 		if (sc->sc_record.sc_intr)
972 			sc->sc_record.sc_intr(sc->sc_record.sc_arg);
973 
974 		/* clear interrupts */
975 		CH_WRITE1(sc, ch, AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
976 
977 		i++;
978 	}
979 	ch = &sc->sc_play;
980 	r = CH_READ1(sc, ch, AUVIA_RP_STAT);
981 	if (r & AUVIA_RPSTAT_INTR) {
982 		if (sc->sc_play.sc_intr)
983 			sc->sc_play.sc_intr(sc->sc_play.sc_arg);
984 
985 		/* clear interrupts */
986 		CH_WRITE1(sc, ch, AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
987 
988 		i++;
989 	}
990 	mtx_leave(&audio_lock);
991 	return (i? 1 : 0);
992 }
993 
994 
995 int
996 auvia_resume(struct auvia_softc *sc)
997 {
998 	pci_conf_read(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK);
999 	pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK,
1000 	    sc->sc_pci_junk);
1001 
1002 	ac97_resume(&sc->host_if, sc->codec_if);
1003 
1004 	return (0);
1005 }
1006 
1007