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