xref: /openbsd/sys/dev/pci/auvia.c (revision 771fbea0)
1 /*	$OpenBSD: auvia.c,v 1.60 2019/12/01 21:14:13 fcambus 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 void	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 
233 	if (act == DVACT_RESUME)
234 		auvia_resume(sc);
235 	return (config_activate_children(self, act));
236 }
237 
238 void
239 auvia_attach(struct device *parent, struct device *self, void *aux)
240 {
241 	struct pci_attach_args *pa = aux;
242 	struct auvia_softc *sc = (struct auvia_softc *) self;
243 	const char *intrstr = NULL;
244 	struct mixer_ctrl ctl;
245 	pci_chipset_tag_t pc = pa->pa_pc;
246 	pcitag_t pt = pa->pa_tag;
247 	pci_intr_handle_t ih;
248 	bus_size_t iosize;
249 	pcireg_t pr;
250 	int r, i;
251 
252 	sc->sc_play.sc_base = AUVIA_PLAY_BASE;
253 	sc->sc_record.sc_base = AUVIA_RECORD_BASE;
254 	if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT8233_AC97) {
255 		sc->sc_flags |= AUVIA_FLAGS_VT8233;
256 		sc->sc_play.sc_base = VIA8233_MP_BASE;
257 		sc->sc_record.sc_base = VIA8233_WR_BASE;
258 	}
259 
260 	if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
261 	    &sc->sc_ioh, NULL, &iosize, 0)) {
262 		printf(": can't map i/o space\n");
263 		return;
264 	}
265 
266 	sc->sc_dmat = pa->pa_dmat;
267 	sc->sc_pc = pc;
268 	sc->sc_pt = pt;
269 
270 	if (pci_intr_map(pa, &ih)) {
271 		printf(": couldn't map interrupt\n");
272 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
273 		return;
274 	}
275 	intrstr = pci_intr_string(pc, ih);
276 
277 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO | IPL_MPSAFE,
278 	    auvia_intr, sc, sc->sc_dev.dv_xname);
279 	if (sc->sc_ih == NULL) {
280 		printf(": couldn't establish interrupt");
281 		if (intrstr != NULL)
282 			printf(" at %s", intrstr);
283 		printf("\n");
284 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
285 		return;
286 	}
287 
288 	printf(": %s\n", intrstr);
289 
290 	/* disable SBPro compat & others */
291 	pr = pci_conf_read(pc, pt, AUVIA_PCICONF_JUNK);
292 
293 	pr &= ~AUVIA_PCICONF_ENABLES; /* clear compat function enables */
294 	/* XXX what to do about MIDI, FM, joystick? */
295 
296 	pr |= (AUVIA_PCICONF_ACLINKENAB | AUVIA_PCICONF_ACNOTRST |
297 	    AUVIA_PCICONF_ACVSR | AUVIA_PCICONF_ACSGD);
298 
299 	pr &= ~(AUVIA_PCICONF_ACFM | AUVIA_PCICONF_ACSB);
300 
301 	pci_conf_write(pc, pt, AUVIA_PCICONF_JUNK, pr);
302 	sc->sc_pci_junk = pr;
303 
304 	sc->host_if.arg = sc;
305 	sc->host_if.attach = auvia_attach_codec;
306 	sc->host_if.read = auvia_read_codec;
307 	sc->host_if.write = auvia_write_codec;
308 	sc->host_if.reset = auvia_reset_codec;
309 	sc->host_if.spdif_event = auvia_spdif_event;
310 
311 	if ((r = ac97_attach(&sc->host_if)) != 0) {
312 		printf("%s: can't attach codec (error 0x%X)\n",
313 		    sc->sc_dev.dv_xname, r);
314 		pci_intr_disestablish(pc, sc->sc_ih);
315 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
316 		return;
317 	}
318 
319 	/* disable mutes */
320 	for (i = 0; i < 4; i++) {
321 		static struct {
322 			char *class, *device;
323 		} d[] = {
324 			{ AudioCoutputs, AudioNmaster},
325 			{ AudioCinputs, AudioNdac},
326 			{ AudioCinputs, AudioNcd},
327 			{ AudioCrecord, AudioNvolume},
328 		};
329 
330 		ctl.type = AUDIO_MIXER_ENUM;
331 		ctl.un.ord = 0;
332 
333 		ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
334 		    d[i].class, d[i].device, AudioNmute);
335 		auvia_set_port(sc, &ctl);
336 	}
337 
338 	/* set a reasonable default volume */
339 
340 	ctl.type = AUDIO_MIXER_VALUE;
341 	ctl.un.value.num_channels = 2;
342 	ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
343 	ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 199;
344 
345 	ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
346 	    AudioCoutputs, AudioNmaster, NULL);
347 	auvia_set_port(sc, &ctl);
348 
349 	audio_attach_mi(&auvia_hw_if, sc, &sc->sc_dev);
350 	sc->codec_if->vtbl->unlock(sc->codec_if);
351 }
352 
353 
354 int
355 auvia_attach_codec(void *addr, struct ac97_codec_if *cif)
356 {
357 	struct auvia_softc *sc = addr;
358 
359 	sc->codec_if = cif;
360 
361 	return 0;
362 }
363 
364 
365 void
366 auvia_reset_codec(void *addr)
367 {
368 	int i;
369 	struct auvia_softc *sc = addr;
370 	pcireg_t r;
371 
372 	/* perform a codec cold reset */
373 
374 	r = pci_conf_read(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK);
375 
376 	r &= ~AUVIA_PCICONF_ACNOTRST;	/* enable RESET (active low) */
377 	pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
378 	delay(2);
379 
380 	r |= AUVIA_PCICONF_ACNOTRST;	/* disable RESET (inactive high) */
381 	pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
382 	delay(200);
383 
384 	for (i = 500000; i != 0 && !(pci_conf_read(sc->sc_pc, sc->sc_pt,
385 		AUVIA_PCICONF_JUNK) & AUVIA_PCICONF_PRIVALID); i--)
386 		DELAY(1);
387 	if (i == 0)
388 		printf("%s: codec reset timed out\n", sc->sc_dev.dv_xname);
389 }
390 
391 
392 int
393 auvia_waitready_codec(struct auvia_softc *sc)
394 {
395 	int i;
396 
397 	/* poll until codec not busy */
398 	for (i = 0; (i < TIMEOUT) && (bus_space_read_4(sc->sc_iot, sc->sc_ioh,
399 	     AUVIA_CODEC_CTL) & AUVIA_CODEC_BUSY); i++)
400 		delay(1);
401 
402 	if (i >= TIMEOUT) {
403 		printf("%s: codec busy\n", sc->sc_dev.dv_xname);
404 		return 1;
405 	}
406 
407 	return 0;
408 }
409 
410 
411 int
412 auvia_waitvalid_codec(struct auvia_softc *sc)
413 {
414 	int i;
415 
416 	/* poll until codec valid */
417 	for (i = 0; (i < TIMEOUT) && !(bus_space_read_4(sc->sc_iot, sc->sc_ioh,
418 	     AUVIA_CODEC_CTL) & AUVIA_CODEC_PRIVALID); i++)
419 		delay(1);
420 
421 	if (i >= TIMEOUT) {
422 		printf("%s: codec invalid\n", sc->sc_dev.dv_xname);
423 		return 1;
424 	}
425 
426 	return 0;
427 }
428 
429 
430 int
431 auvia_write_codec(void *addr, u_int8_t reg, u_int16_t val)
432 {
433 	struct auvia_softc *sc = addr;
434 
435 	if (auvia_waitready_codec(sc))
436 		return 1;
437 
438 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
439 	    AUVIA_CODEC_PRIVALID | AUVIA_CODEC_INDEX(reg) | val);
440 
441 	return 0;
442 }
443 
444 
445 int
446 auvia_read_codec(void *addr, u_int8_t reg, u_int16_t *val)
447 {
448 	struct auvia_softc *sc = addr;
449 
450 	if (auvia_waitready_codec(sc))
451 		return 1;
452 
453 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
454 	    AUVIA_CODEC_PRIVALID | AUVIA_CODEC_READ | AUVIA_CODEC_INDEX(reg));
455 
456 	if (auvia_waitready_codec(sc))
457 		return 1;
458 
459 	if (auvia_waitvalid_codec(sc))
460 		return 1;
461 
462 	*val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL);
463 
464 	return 0;
465 }
466 
467 
468 void
469 auvia_spdif_event(void *addr, int flag)
470 {
471 	struct auvia_softc *sc = addr;
472 	sc->sc_spdif = flag;
473 }
474 
475 int
476 auvia_open(void *addr, int flags)
477 {
478 	struct auvia_softc *sc = addr;
479 	sc->codec_if->vtbl->lock(sc->codec_if);
480 	return 0;
481 }
482 
483 
484 void
485 auvia_close(void *addr)
486 {
487 	struct auvia_softc *sc = addr;
488 	sc->codec_if->vtbl->unlock(sc->codec_if);
489 
490 	/* XXX: already called by audio_close() */
491 	auvia_halt_output(sc);
492 	auvia_halt_input(sc);
493 
494 	sc->sc_play.sc_intr = NULL;
495 	sc->sc_record.sc_intr = NULL;
496 }
497 
498 
499 void
500 auvia_set_params_sub(struct auvia_softc *sc, struct auvia_softc_chan *ch,
501 		     struct audio_params *p)
502 {
503 	u_int32_t v;
504 	u_int16_t regval;
505 
506 	if (!(sc->sc_flags & AUVIA_FLAGS_VT8233)) {
507 		regval = (p->channels == 2 ? AUVIA_RPMODE_STEREO : 0)
508 			| (p->precision == 16 ?
509 				AUVIA_RPMODE_16BIT : 0)
510 			| AUVIA_RPMODE_INTR_FLAG | AUVIA_RPMODE_INTR_EOL
511 			| AUVIA_RPMODE_AUTOSTART;
512 		ch->sc_reg = regval;
513 	} else if (ch->sc_base != VIA8233_MP_BASE) {
514 		v = CH_READ4(sc, ch, VIA8233_RP_RATEFMT);
515 		v &= ~(VIA8233_RATEFMT_48K | VIA8233_RATEFMT_STEREO
516 			| VIA8233_RATEFMT_16BIT);
517 
518 		v |= VIA8233_RATEFMT_48K * (p->sample_rate / 20)
519 			/ (48000 / 20);
520 		if (p->channels == 2)
521 			v |= VIA8233_RATEFMT_STEREO;
522 		if (p->precision == 16)
523 			v |= VIA8233_RATEFMT_16BIT;
524 
525 		CH_WRITE4(sc, ch, VIA8233_RP_RATEFMT, v);
526 	} else {
527 		static const u_int32_t slottab[7] =
528 			{ 0, 0xff000011, 0xff000021, 0,
529 			  0xff004321, 0, 0xff436521};
530 
531 		regval = (p->precision == 16
532 			? VIA8233_MP_FORMAT_16BIT : VIA8233_MP_FORMAT_8BIT)
533 			| (p->channels << 4);
534 		CH_WRITE1(sc, ch, VIA8233_OFF_MP_FORMAT, regval);
535 		CH_WRITE4(sc, ch, VIA8233_OFF_MP_STOP, slottab[p->channels]);
536 	}
537 }
538 
539 int
540 auvia_set_params(void *addr, int setmode, int usemode,
541     struct audio_params *play, struct audio_params *rec)
542 {
543 	struct auvia_softc *sc = addr;
544 	struct auvia_softc_chan *ch;
545 	struct audio_params *p;
546 	struct ac97_codec_if* codec = sc->codec_if;
547 	int reg, mode;
548 	u_int16_t ext_id;
549 
550 	/* for mode in (RECORD, PLAY) */
551 	for (mode = AUMODE_RECORD; mode != -1;
552 	     mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
553 		if ((setmode & mode) == 0)
554 			continue;
555 
556 		if (mode == AUMODE_PLAY) {
557 			p = play;
558 			ch = &sc->sc_play;
559 			reg = AC97_REG_PCM_FRONT_DAC_RATE;
560 		} else {
561 			p = rec;
562 			ch = &sc->sc_record;
563 			reg = AC97_REG_PCM_LR_ADC_RATE;
564 		}
565 
566 		if (ch->sc_base == VIA8233_MP_BASE && mode == AUMODE_PLAY) {
567 			ext_id = codec->vtbl->get_caps(codec);
568 			if (p->channels == 1) {
569 				/* ok */
570 			} else if (p->channels == 2) {
571 				/* ok */
572 			} else if (p->channels == 4
573 				&& ext_id & AC97_EXT_AUDIO_SDAC) {
574 				/* ok */
575 			} else if (p->channels == 6
576 				&& (ext_id & AC97_BITS_6CH) == AC97_BITS_6CH) {
577 				/* ok */
578 			} else {
579 				p->channels = 2;
580 			}
581 		} else {
582 			if (p->channels > 2)
583 				p->channels = 2;
584 		}
585 
586 		if (p->sample_rate < 4000)
587 			p->sample_rate = 4000;
588 		if (p->sample_rate > 48000)
589 			p->sample_rate = 48000;
590 		if (p->precision > 16)
591 			p->precision = 16;
592 
593 		/* XXX only 16-bit 48kHz slinear_le if s/pdif enabled ? */
594 		if (sc->sc_spdif) {
595 			p->sample_rate = 48000;
596 			p->precision = 16;
597 			p->encoding = AUDIO_ENCODING_SLINEAR_LE;
598 		}
599 
600 		/* XXX only 16-bit 48kHz slinear_le if s/pdif enabled ? */
601 		if (sc->sc_spdif &&
602 		    ((p->sample_rate != 48000) || (p->precision != 16) ||
603 		    (p->encoding != AUDIO_ENCODING_SLINEAR_LE)))
604 			return (EINVAL);
605 
606 		if (AC97_IS_FIXED_RATE(codec)) {
607  			p->sample_rate = AC97_SINGLE_RATE;
608  		} else {
609 			if (codec->vtbl->set_rate(codec, reg, &p->sample_rate))
610 				return (EINVAL);
611 
612 			if (ch->sc_base == VIA8233_MP_BASE &&
613 			    mode == AUMODE_PLAY) {
614 				reg = AC97_REG_PCM_SURR_DAC_RATE;
615 				if (p->channels >= 4
616 				    && codec->vtbl->set_rate(codec, reg,
617 				    &p->sample_rate))
618 					return (EINVAL);
619 				reg = AC97_REG_PCM_LFE_DAC_RATE;
620 				if (p->channels == 6
621 				    && codec->vtbl->set_rate(codec, reg,
622 				    &p->sample_rate))
623  				return (EINVAL);
624 			}
625  		}
626 
627 		switch (p->encoding) {
628 		case AUDIO_ENCODING_SLINEAR_LE:
629 			if (p->precision != 16)
630 				return EINVAL;
631 			break;
632 		case AUDIO_ENCODING_ULINEAR_LE:
633 		case AUDIO_ENCODING_ULINEAR_BE:
634 			if (p->precision != 8)
635 				return EINVAL;
636 			break;
637 		default:
638 			return (EINVAL);
639 		}
640 		auvia_set_params_sub(sc, ch, p);
641 
642 		p->bps = AUDIO_BPS(p->precision);
643 		p->msb = 1;
644 	}
645 
646 	return 0;
647 }
648 
649 
650 int
651 auvia_round_blocksize(void *addr, int blk)
652 {
653 	struct auvia_softc *sc = addr;
654 
655 	if (sc->bufsize / blk > AUVIA_DMALIST_MAX)
656 		blk = sc->bufsize / AUVIA_DMALIST_MAX + 1;
657 	return ((blk + 31) & -32);
658 }
659 
660 
661 int
662 auvia_halt_output(void *addr)
663 {
664 	struct auvia_softc *sc = addr;
665 	struct auvia_softc_chan *ch = &(sc->sc_play);
666 
667 	CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE);
668 	ch->sc_intr = NULL;
669 	return 0;
670 }
671 
672 
673 int
674 auvia_halt_input(void *addr)
675 {
676 	struct auvia_softc *sc = addr;
677 	struct auvia_softc_chan *ch = &(sc->sc_record);
678 
679 	CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE);
680 	ch->sc_intr = NULL;
681 	return 0;
682 }
683 
684 
685 int
686 auvia_set_port(void *addr, mixer_ctrl_t *cp)
687 {
688 	struct auvia_softc *sc = addr;
689 
690 	return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
691 }
692 
693 
694 int
695 auvia_get_port(void *addr, mixer_ctrl_t *cp)
696 {
697 	struct auvia_softc *sc = addr;
698 
699 	return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
700 }
701 
702 
703 int
704 auvia_query_devinfo(void *addr, mixer_devinfo_t *dip)
705 {
706 	struct auvia_softc *sc = addr;
707 
708 	return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
709 }
710 
711 
712 void *
713 auvia_malloc(void *addr, int direction, size_t size, int pool, int flags)
714 {
715 	struct auvia_softc *sc = addr;
716 	struct auvia_dma *p;
717 	int error;
718 	int rseg;
719 
720 	p = malloc(sizeof(*p), pool, flags);
721 	if (!p)
722 		return 0;
723 
724 	p->size = size;
725 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg,
726 	    1, &rseg, BUS_DMA_NOWAIT)) != 0) {
727 		printf("%s: unable to allocate dma, error = %d\n",
728 		    sc->sc_dev.dv_xname, error);
729 		goto fail_alloc;
730 	}
731 
732 	if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
733 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
734 		printf("%s: unable to map dma, error = %d\n",
735 		    sc->sc_dev.dv_xname, error);
736 		goto fail_map;
737 	}
738 
739 	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
740 	    BUS_DMA_NOWAIT, &p->map)) != 0) {
741 		printf("%s: unable to create dma map, error = %d\n",
742 		    sc->sc_dev.dv_xname, error);
743 		goto fail_create;
744 	}
745 
746 	if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
747 	    BUS_DMA_NOWAIT)) != 0) {
748 		printf("%s: unable to load dma map, error = %d\n",
749 		    sc->sc_dev.dv_xname, error);
750 		goto fail_load;
751 	}
752 
753 	p->next = sc->sc_dmas;
754 	sc->sc_dmas = p;
755 
756 	return p->addr;
757 
758 
759 fail_load:
760 	bus_dmamap_destroy(sc->sc_dmat, p->map);
761 fail_create:
762 	bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
763 fail_map:
764 	bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
765 fail_alloc:
766 	free(p, pool, sizeof(*p));
767 	return 0;
768 }
769 
770 
771 void
772 auvia_free(void *addr, void *ptr, int pool)
773 {
774 	struct auvia_softc *sc = addr;
775 	struct auvia_dma **pp, *p;
776 
777 	for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
778 		if (p->addr == ptr) {
779 			bus_dmamap_unload(sc->sc_dmat, p->map);
780 			bus_dmamap_destroy(sc->sc_dmat, p->map);
781 			bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
782 			bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
783 
784 			*pp = p->next;
785 			free(p, pool, sizeof(*p));
786 			return;
787 		}
788 
789 	panic("auvia_free: trying to free unallocated memory");
790 }
791 
792 size_t
793 auvia_round_buffersize(void *addr, int direction, size_t bufsize)
794 {
795 	struct auvia_softc *sc = addr;
796 
797 	sc->bufsize = bufsize;
798 	return bufsize;
799 }
800 
801 int
802 auvia_get_props(void *addr)
803 {
804 	int props;
805 
806 	props = AUDIO_PROP_MMAP|AUDIO_PROP_INDEPENDENT|AUDIO_PROP_FULLDUPLEX;
807 
808 	return  props;
809 }
810 
811 
812 int
813 auvia_build_dma_ops(struct auvia_softc *sc, struct auvia_softc_chan *ch,
814     struct auvia_dma *p, void *start, void *end, int blksize)
815 {
816 	struct auvia_dma_op *op;
817 	struct auvia_dma *dp;
818 	bus_addr_t s;
819 	size_t l;
820 	int segs;
821 
822 	s = p->map->dm_segs[0].ds_addr;
823 	l = (vaddr_t)end - (vaddr_t)start;
824 	segs = howmany(l, blksize);
825 	if (segs > AUVIA_DMALIST_MAX) {
826 		panic("%s: build_dma_ops: too many DMA segments",
827 			    sc->sc_dev.dv_xname);
828 	}
829 
830 	if (segs > ch->sc_dma_op_count) {
831 		/* if old list was too small, free it */
832 		if (ch->sc_dma_ops)
833 			auvia_free(sc, ch->sc_dma_ops, M_DEVBUF);
834 
835 		ch->sc_dma_ops = auvia_malloc(sc, 0,
836 		    sizeof(struct auvia_dma_op) * segs, M_DEVBUF, M_WAITOK);
837 
838 		for (dp = sc->sc_dmas; dp &&
839 		     dp->addr != (void *)(ch->sc_dma_ops); dp = dp->next)
840 			;
841 
842 		if (!dp)
843 			panic("%s: build_dma_ops: where'd my memory go??? "
844 			    "address (%p)", sc->sc_dev.dv_xname,
845 			    ch->sc_dma_ops);
846 
847 		ch->sc_dma_op_count = segs;
848 		ch->sc_dma_ops_dma = dp;
849 	}
850 
851 	op = ch->sc_dma_ops;
852 
853 	while (l) {
854 		op->ptr = htole32(s);
855 		l = l - min(l, blksize);
856 		/* if last block */
857 		op->flags = htole32((l? AUVIA_DMAOP_FLAG : AUVIA_DMAOP_EOL) | blksize);
858 		s += blksize;
859 		op++;
860 	}
861 
862 	return 0;
863 }
864 
865 
866 int
867 auvia_trigger_output(void *addr, void *start, void *end, int blksize,
868     void (*intr)(void *), void *arg, struct audio_params *param)
869 {
870 	struct auvia_softc *sc = addr;
871 	struct auvia_softc_chan *ch = &(sc->sc_play);
872 	struct auvia_dma *p;
873 
874 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
875 		;
876 
877 	if (!p)
878 		panic("auvia_trigger_output: request with bad start "
879 		    "address (%p)", start);
880 
881 	if (auvia_build_dma_ops(sc, ch, p, start, end, blksize)) {
882 		return 1;
883 	}
884 
885 	ch->sc_intr = intr;
886 	ch->sc_arg = arg;
887 
888 	CH_WRITE4(sc, ch, AUVIA_RP_DMAOPS_BASE,
889 	    ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
890 	mtx_enter(&audio_lock);
891 	if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
892 		if (ch->sc_base != VIA8233_MP_BASE) {
893 			CH_WRITE1(sc, ch, VIA8233_RP_DXS_LVOL, 0);
894 			CH_WRITE1(sc, ch, VIA8233_RP_DXS_RVOL, 0);
895 		}
896 		CH_WRITE1(sc, ch, AUVIA_RP_CONTROL,
897 		    AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART |
898 		    AUVIA_RPCTRL_STOP  | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
899 	} else {
900 		CH_WRITE1(sc, ch, AUVIA_RP_MODE, ch->sc_reg);
901 		CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_START);
902 	}
903 	mtx_leave(&audio_lock);
904 	return 0;
905 }
906 
907 
908 int
909 auvia_trigger_input(void *addr, void *start, void *end, int blksize,
910     void (*intr)(void *), void *arg, struct audio_params *param)
911 {
912 	struct auvia_softc *sc = addr;
913 	struct auvia_softc_chan *ch = &(sc->sc_record);
914 	struct auvia_dma *p;
915 
916 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
917 		;
918 
919 	if (!p)
920 		panic("auvia_trigger_input: request with bad start "
921 		    "address (%p)", start);
922 
923 	if (auvia_build_dma_ops(sc, ch, p, start, end, blksize))
924 		return 1;
925 
926 	ch->sc_intr = intr;
927 	ch->sc_arg = arg;
928 
929 	CH_WRITE4(sc, ch, AUVIA_RP_DMAOPS_BASE,
930 		  ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
931 
932 	mtx_enter(&audio_lock);
933 	if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
934 		if (ch->sc_base != VIA8233_MP_BASE) {
935 			CH_WRITE1(sc, ch, VIA8233_RP_DXS_LVOL, 0);
936 			CH_WRITE1(sc, ch, VIA8233_RP_DXS_RVOL, 0);
937 		}
938 		CH_WRITE1(sc, ch, AUVIA_RP_CONTROL,
939 		    AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART |
940 		    AUVIA_RPCTRL_STOP  | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
941 	} else {
942 		CH_WRITE1(sc, ch, AUVIA_RP_MODE, ch->sc_reg);
943 		CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_START);
944 	}
945 	mtx_leave(&audio_lock);
946 	return 0;
947 }
948 
949 
950 int
951 auvia_intr(void *arg)
952 {
953 	struct auvia_softc *sc = arg;
954 	struct auvia_softc_chan *ch;
955 	u_int8_t r;
956 	int i = 0;
957 
958 	mtx_enter(&audio_lock);
959 	ch = &sc->sc_record;
960 	r = CH_READ1(sc, ch, AUVIA_RP_STAT);
961 	if (r & AUVIA_RPSTAT_INTR) {
962 		if (sc->sc_record.sc_intr)
963 			sc->sc_record.sc_intr(sc->sc_record.sc_arg);
964 
965 		/* clear interrupts */
966 		CH_WRITE1(sc, ch, AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
967 
968 		i++;
969 	}
970 	ch = &sc->sc_play;
971 	r = CH_READ1(sc, ch, AUVIA_RP_STAT);
972 	if (r & AUVIA_RPSTAT_INTR) {
973 		if (sc->sc_play.sc_intr)
974 			sc->sc_play.sc_intr(sc->sc_play.sc_arg);
975 
976 		/* clear interrupts */
977 		CH_WRITE1(sc, ch, AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
978 
979 		i++;
980 	}
981 	mtx_leave(&audio_lock);
982 	return (i? 1 : 0);
983 }
984 
985 void
986 auvia_resume(struct auvia_softc *sc)
987 {
988 	pci_conf_read(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK);
989 	pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK,
990 	    sc->sc_pci_junk);
991 
992 	ac97_resume(&sc->host_if, sc->codec_if);
993 }
994 
995