xref: /openbsd/sys/dev/pci/auglx.c (revision cca36db2)
1 /*      $OpenBSD: auglx.c,v 1.8 2011/07/03 15:47:16 matthew Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
5  * All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
16  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  * AMD CS5536 series AC'97 audio driver.
22  *
23  * The following datasheets were helpful in the development of this
24  * driver:
25  *
26  * AMD Geode LX Processors Data Book
27  * http://www.amd.com/files/connectivitysolutions/geode/geode_lx/\
28  *     33234F_LX_databook.pdf
29  *
30  * AMD Geode CS5536 Companion Device Data Book
31  * http://www.amd.com/files/connectivitysolutions/geode/geode_lx/\
32  *     33238G_cs5536_db.pdf
33  *
34  * Realtek ALC203 Two-Channel AC'97 2.3 Audio Codec
35  * ftp://202.65.194.211/pc/audio/ALC203_DataSheet_1.6.pdf
36  *
37  * This driver is inspired by the auich(4) and auixp(4) drivers, some
38  * of the hardware-independent functionality has been derived from them
39  * (e.g. memory allocation for the upper level, parameter setting).
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
46 #include <sys/audioio.h>
47 
48 #include <machine/bus.h>
49 
50 #include <dev/pci/pcireg.h>
51 #include <dev/pci/pcivar.h>
52 #include <dev/pci/pcidevs.h>
53 #include <dev/audio_if.h>
54 #include <dev/mulaw.h>
55 #include <dev/auconv.h>
56 
57 #include <dev/ic/ac97.h>
58 
59 #define AUGLX_ACC_BAR		0x10
60 
61 /* ACC Native Registers */
62 #define ACC_GPIO_STATUS		0x00
63 #define ACC_GPIO_CNTL		0x04
64 #define ACC_CODEC_STATUS	0x08
65 #define ACC_CODEC_CNTL		0x0c
66 #define ACC_IRQ_STATUS		0x12
67 #define ACC_ENGINE_CNTL		0x14
68 #define ACC_BM0_CMD		0x20		/* Bus Master 0 Command */
69 #define ACC_BM0_STATUS		0x21		/* Bus Master 0 IRQ Status */
70 #define ACC_BM0_PRD		0x24		/* BM0 PRD Table Address */
71 #define ACC_BM1_CMD		0x28		/* Bus Master 1 Command */
72 #define ACC_BM1_STATUS		0x29		/* Bus Master 1 IRQ Status */
73 #define ACC_BM1_PRD		0x2c		/* BM1 PRD Table Address */
74 #define ACC_BM2_CMD		0x30		/* Bus Master 2 Command */
75 #define ACC_BM2_STATUS		0x31		/* Bus Master 2 IRQ Status */
76 #define ACC_BM2_PRD		0x34		/* BM2 PRD Table Address */
77 #define ACC_BM3_CMD		0x38		/* Bus Master 3 Command */
78 #define ACC_BM3_STATUS		0x39		/* Bus Master 3 IRQ Status */
79 #define ACC_BM3_PRD		0x3c		/* BM3 PRD Table Address */
80 #define ACC_BM4_CMD		0x40		/* Bus Master 4 Command */
81 #define ACC_BM4_STATUS		0x41		/* Bus Master 4 IRQ Status */
82 #define ACC_BM4_PRD		0x44		/* BM4 PRD Table Address */
83 #define ACC_BM5_CMD		0x48		/* Bus Master 5 Command */
84 #define ACC_BM5_STATUS		0x49		/* Bus Master 5 IRQ Status */
85 #define ACC_BM5_PRD		0x4c		/* BM5 PRD Table Address */
86 #define ACC_BM6_CMD		0x50		/* Bus Master 6 Command */
87 #define ACC_BM6_STATUS		0x51		/* Bus Master 6 IRQ Status */
88 #define ACC_BM6_PRD		0x54		/* BM6 PRD Table Address */
89 #define ACC_BM7_CMD		0x58		/* Bus Master 7 Command */
90 #define ACC_BM7_STATUS		0x59		/* Bus Master 7 IRQ Status */
91 #define ACC_BM7_PRD		0x5c		/* BM7 PRD Table Address */
92 #define ACC_BM0_PNTR		0x60		/* Bus Master 0 DMA Pointer */
93 #define ACC_BM1_PNTR		0x64		/* Bus Master 1 DMA Pointer */
94 #define ACC_BM2_PNTR		0x68		/* Bus Master 2 DMA Pointer */
95 #define ACC_BM3_PNTR		0x6c		/* Bus Master 3 DMA Pointer */
96 #define ACC_BM4_PNTR		0x70		/* Bus Master 4 DMA Pointer */
97 #define ACC_BM5_PNTR		0x74		/* Bus Master 5 DMA Pointer */
98 #define ACC_BM6_PNTR		0x78		/* Bus Master 6 DMA Pointer */
99 #define ACC_BM7_PNTR		0x7c		/* Bus Master 7 DMA Pointer */
100 
101 /* ACC_IRQ_STATUS Bit Definitions */
102 #define BM7_IRQ_STS	0x0200	/* Audio Bus Master 7 IRQ Status */
103 #define BM6_IRQ_STS	0x0100	/* Audio Bus Master 6 IRQ Status */
104 #define BM5_IRQ_STS	0x0080	/* Audio Bus Master 5 IRQ Status */
105 #define BM4_IRQ_STS	0x0040	/* Audio Bus Master 4 IRQ Status */
106 #define BM3_IRQ_STS	0x0020	/* Audio Bus Master 3 IRQ Status */
107 #define BM2_IRQ_STS	0x0010	/* Audio Bus Master 2 IRQ Status */
108 #define BM1_IRQ_STS	0x0008	/* Audio Bus Master 1 IRQ Status */
109 #define BM0_IRQ_STS	0x0004	/* Audio Bus Master 0 IRQ Status */
110 #define WU_IRQ_STS	0x0002	/* Codec GPIO Wakeup IRQ Status */
111 #define IRQ_STS		0x0001	/* Codec GPIO IRQ Status */
112 
113 /* ACC_ENGINE_CNTL Bit Definitions */
114 #define SSND_MODE	0x00000001	/* Surround Sound (5.1) Sync. Mode */
115 
116 /* ACC_BM[x]_CMD Bit Descriptions */
117 #define BMx_CMD_RW		0x08	/* 0: Mem to codec, 1: codec to mem */
118 #define BMx_CMD_BYTE_ORD	0x04	/* 0: Little Endian, 1: Big Endian */
119 #define BMx_CMD_BM_CTL_DIS	0x00	/* Disable bus master */
120 #define BMx_CMD_BM_CTL_EN	0x01	/* Enable bus master */
121 #define BMx_CMD_BM_CTL_PAUSE	0x03	/* Pause bus master */
122 
123 /* ACC_BM[x]_STATUS Bit Definitions */
124 #define BMx_BM_EOP_ERR		0x02	/* Bus master error */
125 #define BMx_BM_EOP		0x01	/* End of page */
126 
127 /* ACC_CODEC_CNTL Bit Definitions */
128 #define RW_CMD			0x80000000
129 #define PD_PRIM			0x00200000
130 #define PD_SEC			0x00100000
131 #define LNK_SHTDOWN		0x00040000
132 #define LNK_WRM_RST		0x00020000
133 #define CMD_NEW			0x00010000
134 
135 /* ACC_CODEC_STATUS Bit Definitions */
136 #define PRM_RDY_STS		0x00800000
137 #define SEC_RDY_STS		0x00400000
138 #define SDATAIN2_EN		0x00200000
139 #define BM5_SEL			0x00100000
140 #define BM4_SEL			0x00080000
141 #define STS_NEW			0x00020000
142 
143 #define AUGLX_TOUT		1000	/* uSec */
144 
145 #define	AUGLX_DMALIST_MAX	1
146 #define	AUGLX_DMASEG_MAX	65536
147 
148 struct auglx_prd {
149 	u_int32_t	base;
150 	u_int32_t	size;
151 #define AUGLX_PRD_EOT	0x80000000
152 #define AUGLX_PRD_EOP	0x40000000
153 #define AUGLX_PRD_JMP	0x20000000
154 };
155 
156 #define	AUGLX_FIXED_RATE 48000
157 
158 struct auglx_dma {
159 	bus_dmamap_t		 map;
160 	caddr_t			 addr;
161 	bus_dma_segment_t	 segs[AUGLX_DMALIST_MAX];
162 	int			 nsegs;
163 	size_t			 size;
164 	struct auglx_dma	*next;
165 };
166 
167 struct auglx_softc {
168 	struct device		 sc_dev;
169 	void			*sc_ih;
170 
171 	audio_device_t		 sc_audev;
172 
173 	bus_space_tag_t		 sc_iot;
174 	bus_space_handle_t	 sc_ioh;
175 	bus_dma_tag_t		 sc_dmat;
176 
177 	/*
178 	 * The CS5536 ACC has eight bus masters to support 5.1 audio.
179 	 * This driver, however, only supports main playback and recording
180 	 * since I only have a Realtek ALC203 codec available for testing.
181 	 */
182 	struct auglx_ring {
183 		bus_dmamap_t		 sc_prd;
184 		struct auglx_prd	*sc_vprd;
185 		int			 sc_nprd;
186 
187 		size_t			 sc_size;
188 		int			 nsegs;
189 		bus_dma_segment_t	 seg;
190 
191 		void			(*intr)(void *);
192 		void			*arg;
193 	} bm0, bm1;	/* bm0: output, bm1: input */
194 
195 	struct auglx_dma	*sc_dmas;
196 
197 	struct ac97_codec_if	*codec_if;
198 	struct ac97_host_if	 host_if;
199 
200 	int			 sc_dmamap_flags;
201 };
202 
203 #ifdef AUGLX_DEBUG
204 #define	DPRINTF(l,x)	do { if (auglx_debug & (l)) printf x; } while(0)
205 int auglx_debug = 0;
206 #define AUGLX_DBG_ACC	0x0001
207 #define AUGLX_DBG_DMA	0x0002
208 #define AUGLX_DBG_IRQ	0x0004
209 #else
210 #define	DPRINTF(x,y)	/* nothing */
211 #endif
212 
213 struct cfdriver auglx_cd = {
214 	NULL, "auglx", DV_DULL
215 };
216 
217 int auglx_open(void *, int);
218 void auglx_close(void *);
219 int auglx_query_encoding(void *, struct audio_encoding *);
220 int auglx_set_params(void *, int, int, struct audio_params *,
221     struct audio_params *);
222 int auglx_round_blocksize(void *, int);
223 int auglx_halt_output(void *);
224 int auglx_halt_input(void *);
225 int auglx_getdev(void *, struct audio_device *);
226 int auglx_set_port(void *, mixer_ctrl_t *);
227 int auglx_get_port(void *, mixer_ctrl_t *);
228 int auglx_query_devinfo(void *, mixer_devinfo_t *);
229 void *auglx_allocm(void *, int, size_t, int, int);
230 void auglx_freem(void *, void *, int);
231 size_t auglx_round_buffersize(void *, int, size_t);
232 paddr_t auglx_mappage(void *, void *, off_t, int);
233 int auglx_get_props(void *);
234 int auglx_trigger_output(void *, void *, void *, int, void (*)(void *),
235     void *, struct audio_params *);
236 int auglx_trigger_input(void *, void *, void *, int, void (*)(void *),
237     void *, struct audio_params *);
238 int auglx_alloc_cdata(struct auglx_softc *);
239 int auglx_alloc_prd(struct auglx_softc *, size_t, struct auglx_ring *);
240 void auglx_free_prd(struct auglx_softc *sc, struct auglx_ring *bm);
241 int auglx_allocmem(struct auglx_softc *, size_t, size_t, struct auglx_dma *);
242 void auglx_freemem(struct auglx_softc *, struct auglx_dma *);
243 void auglx_get_default_params(void *, int, struct audio_params *);
244 
245 struct audio_hw_if auglx_hw_if = {
246 	auglx_open,
247 	auglx_close,
248 	NULL,			/* drain */
249 	auglx_query_encoding,
250 	auglx_set_params,
251 	auglx_round_blocksize,
252 	NULL,			/* commit_setting */
253 	NULL,			/* init_output */
254 	NULL,			/* init_input */
255 	NULL,			/* start_output */
256 	NULL,			/* start_input */
257 	auglx_halt_output,
258 	auglx_halt_input,
259 	NULL,			/* speaker_ctl */
260 	auglx_getdev,
261 	NULL,			/* getfd */
262 	auglx_set_port,
263 	auglx_get_port,
264 	auglx_query_devinfo,
265 	auglx_allocm,
266 	auglx_freem,
267 	auglx_round_buffersize,
268 	auglx_mappage,
269 	auglx_get_props,
270 	auglx_trigger_output,
271 	auglx_trigger_input,
272 	auglx_get_default_params
273 };
274 
275 int	auglx_match(struct device *, void *, void *);
276 void	auglx_attach(struct device *, struct device *, void *);
277 int	auglx_activate(struct device *, int);
278 int	auglx_intr(void *);
279 
280 int	auglx_attach_codec(void *, struct ac97_codec_if *);
281 int	auglx_read_codec(void *, u_int8_t, u_int16_t *);
282 int	auglx_write_codec(void *, u_int8_t, u_int16_t);
283 void	auglx_reset_codec(void *);
284 enum ac97_host_flags	auglx_flags_codec(void *);
285 
286 struct cfattach auglx_ca = {
287 	sizeof(struct auglx_softc), auglx_match, auglx_attach, NULL,
288 	auglx_activate
289 };
290 
291 const struct pci_matchid auglx_devices[] = {
292 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_CS5536_AUDIO }
293 };
294 
295 int
296 auglx_match(struct device *parent, void *match, void *aux)
297 {
298 	return (pci_matchbyid((struct pci_attach_args *)aux, auglx_devices,
299 	    sizeof(auglx_devices) / sizeof(auglx_devices[0])));
300 }
301 
302 void
303 auglx_attach(struct device *parent, struct device *self, void *aux)
304 {
305 	struct auglx_softc *sc = (struct auglx_softc *)self;
306 	struct pci_attach_args *pa = aux;
307 	bus_size_t bar_size;
308 	pci_intr_handle_t ih;
309 	const char *intrstr;
310 
311 	if (pci_mapreg_map(pa, AUGLX_ACC_BAR, PCI_MAPREG_TYPE_IO, 0,
312 	    &sc->sc_iot, &sc->sc_ioh, NULL, &bar_size, 0)) {
313 		printf(": can't map ACC I/O space\n");
314 		return;
315 	}
316 
317 	sc->sc_dmat = pa->pa_dmat;
318 	sc->sc_dmamap_flags = BUS_DMA_COHERENT;
319 
320 	if (pci_intr_map(pa, &ih)) {
321 		printf(": can't map interrupt");
322 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, bar_size);
323 		return;
324 	}
325 	intrstr = pci_intr_string(pa->pa_pc, ih);
326 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, auglx_intr,
327 				       sc, sc->sc_dev.dv_xname);
328 	if (!sc->sc_ih) {
329 		printf(": can't establish interrupt");
330 		if (intrstr)
331 			printf(" at %s", intrstr);
332 		printf("\n");
333 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, bar_size);
334 		return;
335 	}
336 
337 	strlcpy(sc->sc_audev.name, "CS5536 AC97", sizeof sc->sc_audev.name);
338 	snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version, "0x%02x",
339 		 PCI_REVISION(pa->pa_class));
340 	strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname,
341 		sizeof sc->sc_audev.config);
342 
343 	printf(": %s, %s\n", intrstr, sc->sc_audev.name);
344 
345 	sc->host_if.arg = sc;
346 	sc->host_if.attach = auglx_attach_codec;
347 	sc->host_if.read = auglx_read_codec;
348 	sc->host_if.write = auglx_write_codec;
349 	sc->host_if.reset = auglx_reset_codec;
350 	sc->host_if.flags = auglx_flags_codec;
351 
352 	if (ac97_attach(&sc->host_if) != 0) {
353 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, bar_size);
354 		return;
355 	}
356 	audio_attach_mi(&auglx_hw_if, sc, &sc->sc_dev);
357 }
358 
359 /* Functions to communicate with the AC97 Codec via the ACC */
360 int
361 auglx_read_codec(void *v, u_int8_t reg, u_int16_t *val)
362 {
363 	struct auglx_softc *sc = v;
364 	u_int32_t codec_cntl, codec_status;
365 	int i;
366 
367 	codec_cntl = RW_CMD | ((u_int32_t)reg << 24) | CMD_NEW;
368 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL, codec_cntl);
369 
370 	for (i = AUGLX_TOUT; i; i--) {
371 		codec_cntl = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
372 		    ACC_CODEC_CNTL);
373 		if (!(codec_cntl & CMD_NEW))
374 			break;
375 		delay(1);
376 	}
377 	if (codec_cntl & CMD_NEW) {
378 		printf("%s: codec read timeout after write\n",
379 		    sc->sc_dev.dv_xname);
380 		return -1;
381 	}
382 
383 	for (i = AUGLX_TOUT; i; i--) {
384 		codec_status = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
385 		    ACC_CODEC_STATUS);
386 		if ((codec_status & STS_NEW) && (codec_status >> 24 == reg))
387 			break;
388 		delay(10);
389 	}
390 	if (i == 0) {
391 		printf("%s: codec status read timeout, 0x%08x\n",
392 		    sc->sc_dev.dv_xname, codec_status);
393 		return -1;
394 	}
395 
396 	*val = codec_status & 0xffff;
397 	DPRINTF(AUGLX_DBG_ACC, ("%s: read codec register 0x%02x: 0x%04x\n",
398 	    sc->sc_dev.dv_xname, reg, *val));
399 	return 0;
400 }
401 
402 int
403 auglx_write_codec(void *v, u_int8_t reg, u_int16_t val)
404 {
405 	struct auglx_softc *sc = v;
406 	u_int32_t codec_cntl;
407 	int i;
408 
409 	DPRINTF(AUGLX_DBG_ACC, ("%s: write codec register 0x%02x: 0x%04x\n",
410 	    sc->sc_dev.dv_xname, reg, val));
411 
412 
413 	codec_cntl = ((u_int32_t)reg << 24) | CMD_NEW | val;
414 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL, codec_cntl);
415 
416 	for (i = AUGLX_TOUT; i; i--) {
417 		codec_cntl = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
418 		    ACC_CODEC_CNTL);
419 		if (!(codec_cntl & CMD_NEW))
420 			break;
421 		delay(1);
422 	}
423 	if (codec_cntl & CMD_NEW) {
424 		printf("%s: codec write timeout\n", sc->sc_dev.dv_xname);
425 		return -1;
426 	}
427 
428 	return 0;
429 }
430 
431 int
432 auglx_attach_codec(void *v, struct ac97_codec_if *cif)
433 {
434 	struct auglx_softc *sc = v;
435 
436 	sc->codec_if = cif;
437 	return 0;
438 }
439 
440 void
441 auglx_reset_codec(void *v)
442 {
443 	struct auglx_softc *sc = v;
444 	u_int32_t codec_cntl;
445 	int i;
446 
447 	codec_cntl = LNK_WRM_RST | CMD_NEW;
448 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL, codec_cntl);
449 
450 	for (i = AUGLX_TOUT; i; i--) {
451 		codec_cntl = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
452 		    ACC_CODEC_CNTL);
453 		if (!(codec_cntl & CMD_NEW))
454 			continue;
455 		delay(1);
456 	}
457 	if (codec_cntl & CMD_NEW)
458 		printf("%s: codec reset timeout\n", sc->sc_dev.dv_xname);
459 }
460 
461 enum ac97_host_flags
462 auglx_flags_codec(void *v)
463 {
464 	return 0;
465 }
466 
467 /*
468  * Audio functions
469  */
470 int
471 auglx_open(void *v, int flags)
472 {
473 	return 0;
474 }
475 
476 void
477 auglx_close(void *v)
478 {
479 }
480 
481 
482 int
483 auglx_query_encoding(void *v, struct audio_encoding *aep)
484 {
485 	switch (aep->index) {
486 	case 0:
487 		strlcpy(aep->name, AudioEulinear, sizeof aep->name);
488 		aep->encoding = AUDIO_ENCODING_ULINEAR;
489 		aep->precision = 8;
490 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
491 		break;
492 	case 1:
493 		strlcpy(aep->name, AudioEmulaw, sizeof aep->name);
494 		aep->encoding = AUDIO_ENCODING_ULAW;
495 		aep->precision = 8;
496 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
497 		break;
498 	case 2:
499 		strlcpy(aep->name, AudioEalaw, sizeof aep->name);
500 		aep->encoding = AUDIO_ENCODING_ALAW;
501 		aep->precision = 8;
502 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
503 		break;
504 	case 3:
505 		strlcpy(aep->name, AudioEslinear, sizeof aep->name);
506 		aep->encoding = AUDIO_ENCODING_SLINEAR;
507 		aep->precision = 8;
508 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
509 		break;
510 	case 4:
511 		strlcpy(aep->name, AudioEslinear_le, sizeof aep->name);
512 		aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
513 		aep->precision = 16;
514 		aep->flags = 0;
515 		break;
516 	case 5:
517 		strlcpy(aep->name, AudioEulinear_le, sizeof aep->name);
518 		aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
519 		aep->precision = 16;
520 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
521 		break;
522 	case 6:
523 		strlcpy(aep->name, AudioEslinear_be, sizeof aep->name);
524 		aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
525 		aep->precision = 16;
526 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
527 		break;
528 	case 7:
529 		strlcpy(aep->name, AudioEulinear_be, sizeof aep->name);
530 		aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
531 		aep->precision = 16;
532 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
533 		break;
534 	default:
535 		return EINVAL;
536 	}
537 	aep->bps = AUDIO_BPS(aep->precision);
538 	aep->msb = 1;
539 
540 	return 0;
541 }
542 
543 
544 int
545 auglx_set_params(void *v, int setmode, int usemode, struct audio_params *play,
546     struct audio_params *rec)
547 {
548 	struct auglx_softc *sc = v;
549 	int error;
550 	u_int orate;
551 
552 	if (setmode & AUMODE_PLAY) {
553 		play->factor = 1;
554 		play->sw_code = NULL;
555 		if (play->precision > 16)
556 			play->precision = 16;
557 		if (play->channels > 2)
558 			play->channels = 2;
559 		switch(play->encoding) {
560 		case AUDIO_ENCODING_ULAW:
561 			switch (play->channels) {
562 			case 1:
563 				play->factor = 4;
564 				play->sw_code = mulaw_to_slinear16_le_mts;
565 				break;
566 			case 2:
567 				play->factor = 2;
568 				play->sw_code = mulaw_to_slinear16_le;
569 				break;
570 			default:
571 				return EINVAL;
572 			}
573 			break;
574 		case AUDIO_ENCODING_SLINEAR_LE:
575 			switch (play->precision) {
576 			case 8:
577 				switch (play->channels) {
578 				case 1:
579 					play->factor = 4;
580 					play->sw_code = linear8_to_linear16_le_mts;
581 					break;
582 				case 2:
583 					play->factor = 2;
584 					play->sw_code = linear8_to_linear16_le;
585 					break;
586 				default:
587 					return EINVAL;
588 				}
589 				break;
590 			case 16:
591 				switch (play->channels) {
592 				case 1:
593 					play->factor = 2;
594 					play->sw_code = noswap_bytes_mts;
595 					break;
596 				case 2:
597 					break;
598 				default:
599 					return EINVAL;
600 				}
601 				break;
602 			default:
603 				return (EINVAL);
604 			}
605 			break;
606 		case AUDIO_ENCODING_ULINEAR_LE:
607 			switch (play->precision) {
608 			case 8:
609 				switch (play->channels) {
610 				case 1:
611 					play->factor = 4;
612 					play->sw_code = ulinear8_to_linear16_le_mts;
613 					break;
614 				case 2:
615 					play->factor = 2;
616 					play->sw_code = ulinear8_to_linear16_le;
617 					break;
618 				default:
619 					return EINVAL;
620 				}
621 				break;
622 			case 16:
623 				switch (play->channels) {
624 				case 1:
625 					play->factor = 2;
626 					play->sw_code = change_sign16_le_mts;
627 					break;
628 				case 2:
629 					play->sw_code = change_sign16_le;
630 					break;
631 				default:
632 					return EINVAL;
633 				}
634 				break;
635 			default:
636 				return EINVAL;
637 			}
638 			break;
639 		case AUDIO_ENCODING_ALAW:
640 			switch (play->channels) {
641 			case 1:
642 				play->factor = 4;
643 				play->sw_code = alaw_to_slinear16_le_mts;
644 				break;
645 			case 2:
646 				play->factor = 2;
647 				play->sw_code = alaw_to_slinear16_le;
648 				break;
649 			default:
650 				return EINVAL;
651 			}
652 			break;
653 		case AUDIO_ENCODING_SLINEAR_BE:
654 			switch (play->precision) {
655 			case 8:
656 				switch (play->channels) {
657 				case 1:
658 					play->factor = 4;
659 					play->sw_code = linear8_to_linear16_le_mts;
660 					break;
661 				case 2:
662 					play->factor = 2;
663 					play->sw_code = linear8_to_linear16_le;
664 					break;
665 				default:
666 					return EINVAL;
667 				}
668 				break;
669 			case 16:
670 				switch (play->channels) {
671 				case 1:
672 					play->factor = 2;
673 					play->sw_code = swap_bytes_mts;
674 					break;
675 				case 2:
676 					play->sw_code = swap_bytes;
677 					break;
678 				default:
679 					return EINVAL;
680 				}
681 				break;
682 			default:
683 				return EINVAL;
684 			}
685 			break;
686 		case AUDIO_ENCODING_ULINEAR_BE:
687 			switch (play->precision) {
688 			case 8:
689 				switch (play->channels) {
690 				case 1:
691 					play->factor = 4;
692 					play->sw_code = ulinear8_to_linear16_le_mts;
693 					break;
694 				case 2:
695 					play->factor = 2;
696 					play->sw_code = ulinear8_to_linear16_le;
697 					break;
698 				default:
699 					return EINVAL;
700 				}
701 				break;
702 			case 16:
703 				switch (play->channels) {
704 				case 1:
705 					play->factor = 2;
706 					play->sw_code = swap_bytes_change_sign16_le_mts;
707 					break;
708 				case 2:
709 					play->sw_code = swap_bytes_change_sign16_le;
710 					break;
711 				default:
712 					return EINVAL;
713 				}
714 				break;
715 			default:
716 				return EINVAL;
717 			}
718 			break;
719 		default:
720 			return EINVAL;
721 		}
722 		play->bps = AUDIO_BPS(play->precision);
723 		play->msb = 1;
724 
725 		orate = play->sample_rate;
726 
727 		play->sample_rate = orate;
728 		error = ac97_set_rate(sc->codec_if,
729 		    AC97_REG_PCM_LFE_DAC_RATE, &play->sample_rate);
730 		if (error)
731 			return error;
732 
733 		play->sample_rate = orate;
734 		error = ac97_set_rate(sc->codec_if,
735 		    AC97_REG_PCM_SURR_DAC_RATE, &play->sample_rate);
736 		if (error)
737 			return error;
738 
739 		play->sample_rate = orate;
740 		error = ac97_set_rate(sc->codec_if,
741 		    AC97_REG_PCM_FRONT_DAC_RATE, &play->sample_rate);
742 		if (error)
743 			return error;
744 	}
745 
746 	if (setmode & AUMODE_RECORD) {
747 		rec->factor = 1;
748 		rec->sw_code = 0;
749 		if (rec->precision > 16)
750 			rec->precision = 16;
751 		if (rec->channels > 2)
752 			rec->channels = 2;
753 		switch(rec->encoding) {
754 		case AUDIO_ENCODING_ULAW:
755 			switch (rec->channels) {
756 			case 1:
757 				rec->sw_code = slinear16_to_mulaw_le_stm;
758 				rec->factor = 4;
759 				break;
760 			case 2:
761 				rec->sw_code = slinear16_to_mulaw_le;
762 				rec->factor = 2;
763 				break;
764 			}
765 			break;
766 		case AUDIO_ENCODING_ALAW:
767 			switch (rec->channels) {
768 			case 1:
769 				rec->sw_code = slinear16_to_alaw_le_stm;
770 				rec->factor = 4;
771 				break;
772 			case 2:
773 				rec->sw_code = slinear16_to_alaw_le;
774 				rec->factor = 2;
775 				break;
776 			}
777 			break;
778 		case AUDIO_ENCODING_SLINEAR_LE:
779 			switch (rec->precision) {
780 			case 8:
781 				switch (rec->channels) {
782 				case 1:
783 					rec->sw_code = linear16_to_linear8_le_stm;
784 					rec->factor = 4;
785 					break;
786 				case 2:
787 					rec->sw_code = linear16_to_linear8_le;
788 					rec->factor = 2;
789 					break;
790 				}
791 				break;
792 			case 16:
793 				switch (rec->channels) {
794 				case 1:
795 					rec->sw_code = linear16_decimator;
796 					rec->factor = 2;
797 					break;
798 				case 2:
799 					break;
800 				}
801 				break;
802 			default:
803 				return EINVAL;
804 			}
805 			break;
806 		case AUDIO_ENCODING_ULINEAR_LE:
807 			switch (rec->precision) {
808 			case 8:
809 				switch (rec->channels) {
810 				case 1:
811 					rec->sw_code = linear16_to_ulinear8_le_stm;
812 					rec->factor = 4;
813 					break;
814 				case 2:
815 					rec->sw_code = linear16_to_ulinear8_le;
816 					rec->factor = 2;
817 					break;
818 				}
819 				break;
820 			case 16:
821 				switch (rec->channels) {
822 				case 1:
823 					rec->sw_code = change_sign16_le_stm;
824 					rec->factor = 2;
825 					break;
826 				case 2:
827 					rec->sw_code = change_sign16_le;
828 					break;
829 				}
830 				break;
831 			default:
832 				return EINVAL;
833 			}
834 			break;
835 		case AUDIO_ENCODING_SLINEAR_BE:
836 			switch (rec->precision) {
837 			case 8:
838 				switch (rec->channels) {
839 				case 1:
840 					rec->sw_code = linear16_to_linear8_le_stm;
841 					rec->factor = 4;
842 					break;
843 				case 2:
844 					rec->sw_code = linear16_to_linear8_le;
845 					rec->factor = 2;
846 					break;
847 				}
848 				break;
849 			case 16:
850 				switch (rec->channels) {
851 				case 1:
852 					rec->sw_code = swap_bytes_stm;
853 					rec->factor = 2;
854 					break;
855 				case 2:
856 					rec->sw_code = swap_bytes;
857 					break;
858 				}
859 				break;
860 			default:
861 				return EINVAL;
862 			}
863 			break;
864 		case AUDIO_ENCODING_ULINEAR_BE:
865 			switch (rec->precision) {
866 			case 8:
867 				switch (rec->channels) {
868 				case 1:
869 					rec->sw_code = linear16_to_ulinear8_le_stm;
870 					rec->factor = 4;
871 					break;
872 				case 2:
873 					rec->sw_code = linear16_to_ulinear8_le;
874 					rec->factor = 2;
875 					break;
876 				}
877 				break;
878 			case 16:
879 				switch (rec->channels) {
880 				case 1:
881 					rec->sw_code = change_sign16_swap_bytes_le_stm;
882 					rec->factor = 2;
883 					break;
884 				case 2:
885 					rec->sw_code = change_sign16_swap_bytes_le;
886 					break;
887 				}
888 				break;
889 			default:
890 				return EINVAL;
891 			}
892 			break;
893 		default:
894 			return EINVAL;
895 		}
896 		rec->bps = AUDIO_BPS(rec->precision);
897 		rec->msb = 1;
898 
899 		error = ac97_set_rate(sc->codec_if, AC97_REG_PCM_LR_ADC_RATE,
900 		    &rec->sample_rate);
901 		if (error)
902 			return error;
903 	}
904 
905 	return 0;
906 }
907 
908 int
909 auglx_round_blocksize(void *v, int blk)
910 {
911 	return (blk + 0x3f) & ~0x3f;
912 }
913 
914 int
915 auglx_halt_output(void *v)
916 {
917 	struct auglx_softc *sc = v;
918 
919 	DPRINTF(AUGLX_DBG_DMA, ("%s: halt_output\n", sc->sc_dev.dv_xname));
920 
921 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD, 0x00);
922 	sc->bm0.intr = NULL;
923 	return 0;
924 }
925 
926 int
927 auglx_halt_input(void *v)
928 {
929 	struct auglx_softc *sc = v;
930 
931 	DPRINTF(AUGLX_DBG_DMA,
932 	    ("%s: halt_input\n", sc->sc_dev.dv_xname));
933 
934 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD, 0x00);
935 	sc->bm1.intr = NULL;
936 	return 0;
937 }
938 
939 int
940 auglx_getdev(void *v, struct audio_device *adp)
941 {
942 	struct auglx_softc *sc = v;
943 	*adp = sc->sc_audev;
944 	return 0;
945 }
946 
947 int
948 auglx_set_port(void *v, mixer_ctrl_t *cp)
949 {
950 	struct auglx_softc *sc = v;
951 	return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
952 }
953 
954 int
955 auglx_get_port(void *v, mixer_ctrl_t *cp)
956 {
957 	struct auglx_softc *sc = v;
958 	return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
959 }
960 
961 int
962 auglx_query_devinfo(void *v, mixer_devinfo_t *dp)
963 {
964 	struct auglx_softc *sc = v;
965 	return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp);
966 }
967 
968 void *
969 auglx_allocm(void *v, int direction, size_t size, int pool, int flags)
970 {
971 	struct auglx_softc *sc = v;
972 	struct auglx_dma *p;
973 	int error;
974 
975 	DPRINTF(AUGLX_DBG_DMA, ("%s: request buffer of size %ld, dir %d\n",
976 	    sc->sc_dev.dv_xname, size, direction));
977 
978 	/* can only use 1 segment */
979 	if (size > AUGLX_DMASEG_MAX) {
980 		DPRINTF(AUGLX_DBG_DMA,
981 		    ("%s: requested buffer size too large: %d", \
982 		    sc->sc_dev.dv_xname, size));
983 		return NULL;
984 	}
985 
986 	p = malloc(sizeof(*p), pool, flags | M_ZERO);
987 	if (!p)
988 		return NULL;
989 
990 	error = auglx_allocmem(sc, size, PAGE_SIZE, p);
991 	if (error) {
992 		free(p, pool);
993 		return NULL;
994 	}
995 
996 	p->next = sc->sc_dmas;
997 	sc->sc_dmas = p;
998 
999 	return p->addr;
1000 }
1001 
1002 void
1003 auglx_freem(void *v, void *ptr, int pool)
1004 {
1005 	struct auglx_softc *sc;
1006 	struct auglx_dma *p, **pp;
1007 
1008 	sc = v;
1009 	for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
1010 		if (p->addr == ptr) {
1011 			auglx_freemem(sc, p);
1012 			*pp = p->next;
1013 			free(p, pool);
1014 			return;
1015 		}
1016 	}
1017 }
1018 
1019 
1020 size_t
1021 auglx_round_buffersize(void *v, int direction, size_t size)
1022 {
1023 	if (size > AUGLX_DMASEG_MAX)
1024 		size = AUGLX_DMASEG_MAX;
1025 
1026 	return size;
1027 }
1028 
1029 paddr_t
1030 auglx_mappage(void *v, void *mem, off_t off, int prot)
1031 {
1032 	struct auglx_softc *sc = v;
1033 	struct auglx_dma *p;
1034 
1035 	if (off < 0)
1036 		return -1;
1037 
1038 	for (p = sc->sc_dmas; p && p->addr != mem; p = p->next);
1039 	if (!p)
1040 		return -1;
1041 
1042 	return bus_dmamem_mmap(sc->sc_dmat, p->segs, p->nsegs,
1043 	    off, prot, BUS_DMA_WAITOK);
1044 }
1045 
1046 int
1047 auglx_get_props(void *v)
1048 {
1049 	return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
1050 }
1051 
1052 int
1053 auglx_intr(void *v)
1054 {
1055 	struct auglx_softc *sc = v;
1056 	u_int16_t irq_sts;
1057 	u_int8_t bm_sts;
1058 
1059 	irq_sts = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ACC_IRQ_STATUS);
1060 	if (irq_sts == 0)
1061 		return 0;
1062 
1063 	if (irq_sts & BM0_IRQ_STS) {
1064 		bm_sts = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
1065 		    ACC_BM0_STATUS);
1066 		if (sc->bm0.intr) {
1067 			sc->bm0.intr(sc->bm0.arg);
1068 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
1069 			    BMx_CMD_BM_CTL_EN);
1070 		}
1071 	} else if (irq_sts & BM1_IRQ_STS) {
1072 		bm_sts = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
1073 		    ACC_BM1_STATUS);
1074 		if (sc->bm1.intr) {
1075 			sc->bm1.intr(sc->bm1.arg);
1076 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD,
1077 			    BMx_CMD_RW | BMx_CMD_BM_CTL_EN);
1078 		}
1079 	} else {
1080 		DPRINTF(AUGLX_DBG_IRQ, ("%s: stray intr, status = 0x%04x\n",
1081 		    sc->sc_dev.dv_xname, irq_sts));
1082 		return -1;
1083 	}
1084 	return 1;
1085 }
1086 
1087 int
1088 auglx_trigger_output(void *v, void *start, void *end, int blksize,
1089     void (*intr)(void *), void *arg, struct audio_params *param)
1090 {
1091 	struct auglx_softc *sc = v;
1092 	struct auglx_dma *p;
1093 	size_t size;
1094 	u_int32_t addr;
1095 	int i, nprd;
1096 
1097 	size = (size_t)((caddr_t)end - (caddr_t)start);
1098 	DPRINTF(AUGLX_DBG_DMA, ("%s: trigger_output, %p 0x%08x bytes, "
1099 	    "blksize 0x%04x\n", sc->sc_dev.dv_xname, start, size, blksize));
1100 
1101 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1102 	if (!p) {
1103 		DPRINTF(AUGLX_DBG_DMA, ("%s dma reg not found\n",
1104 		    sc->sc_dev.dv_xname));
1105 		return -1;
1106 	}
1107 
1108 	/* set up the PRDs */
1109 	nprd = size / blksize;
1110 	if (sc->bm0.sc_nprd != nprd + 1) {
1111 		if (sc->bm0.sc_nprd > 0)
1112 			auglx_free_prd(sc, &sc->bm0);
1113 		sc->bm0.sc_nprd = nprd + 1;
1114 		auglx_alloc_prd(sc,
1115 		    sc->bm0.sc_nprd * sizeof(struct auglx_prd), &sc->bm0);
1116 	}
1117 	DPRINTF(AUGLX_DBG_DMA, ("%s: nprd = %d\n", sc->sc_dev.dv_xname,
1118 	    nprd));
1119 	addr = p->segs->ds_addr;
1120 	for (i = 0; i < nprd; i++) {
1121 		sc->bm0.sc_vprd[i].base = addr;
1122 		sc->bm0.sc_vprd[i].size = blksize | AUGLX_PRD_EOP;
1123 		addr += blksize;
1124 	}
1125 	sc->bm0.sc_vprd[i].base = sc->bm0.sc_prd->dm_segs[0].ds_addr;
1126 	sc->bm0.sc_vprd[i].size = AUGLX_PRD_JMP;
1127 
1128 #ifdef AUGLX_DEBUG
1129 	for (i = 0; i < sc->bm0.sc_nprd; i++)
1130 		DPRINTF(AUGLX_DBG_DMA, ("%s: PRD[%d].base = %p, size %p\n",
1131 		    sc->sc_dev.dv_xname, i, sc->bm0.sc_vprd[i].base,
1132 		    sc->bm0.sc_vprd[i].size));
1133 #endif
1134 	sc->bm0.intr = intr;
1135 	sc->bm0.arg = arg;
1136 
1137 	/* Program the BM0 PRD register */
1138 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_PRD,
1139 	    sc->bm0.sc_prd->dm_segs[0].ds_addr);
1140 	/* Start Audio Bus Master 0 */
1141 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
1142 	    BMx_CMD_BM_CTL_EN);
1143 	return 0;
1144 }
1145 
1146 int
1147 auglx_trigger_input(void *v, void *start, void *end, int blksize,
1148     void (*intr)(void *), void * arg, struct audio_params *param)
1149 {
1150 	struct auglx_softc *sc = v;
1151 	struct auglx_dma *p;
1152 	size_t size;
1153 	u_int32_t addr;
1154 	int i, nprd;
1155 
1156 	size = (size_t)((caddr_t)end - (caddr_t)start);
1157 	DPRINTF(AUGLX_DBG_DMA, ("%s: trigger_input, %p 0x%08x bytes, "
1158 	    "blksize 0x%04x\n", sc->sc_dev.dv_xname, start, size, blksize));
1159 
1160 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1161 	if (!p) {
1162 		DPRINTF(AUGLX_DBG_DMA, ("%s dma reg not found\n",
1163 		    sc->sc_dev.dv_xname));
1164 		return -1;
1165 	}
1166 
1167 	/* set up the PRDs */
1168 	nprd = size / blksize;
1169 	if (sc->bm1.sc_nprd != nprd + 1) {
1170 		if (sc->bm1.sc_nprd > 0)
1171 			auglx_free_prd(sc, &sc->bm1);
1172 		sc->bm1.sc_nprd = nprd + 1;
1173 		auglx_alloc_prd(sc,
1174 		    sc->bm1.sc_nprd * sizeof(struct auglx_prd), &sc->bm1);
1175 	}
1176 	DPRINTF(AUGLX_DBG_DMA, ("%s: nprd = %d\n", sc->sc_dev.dv_xname,
1177 	    nprd));
1178 	addr = p->segs->ds_addr;
1179 	for (i = 0; i < nprd; i++) {
1180 		sc->bm1.sc_vprd[i].base = addr;
1181 		sc->bm1.sc_vprd[i].size = blksize | AUGLX_PRD_EOP;
1182 		addr += blksize;
1183 	}
1184 	sc->bm1.sc_vprd[i].base = sc->bm1.sc_prd->dm_segs[0].ds_addr;
1185 	sc->bm1.sc_vprd[i].size = AUGLX_PRD_JMP;
1186 
1187 #ifdef AUGLX_DEBUG
1188 	for (i = 0; i < sc->bm1.sc_nprd; i++)
1189 		DPRINTF(AUGLX_DBG_DMA, ("%s: PRD[%d].base = %p, size %p\n",
1190 		    sc->sc_dev.dv_xname, i, sc->bm1.sc_vprd[i].base,
1191 		    sc->bm1.sc_vprd[i].size));
1192 #endif
1193 	sc->bm1.intr = intr;
1194 	sc->bm1.arg = arg;
1195 
1196 	/* Program the BM1 PRD register */
1197 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM1_PRD,
1198 	    sc->bm1.sc_prd->dm_segs[0].ds_addr);
1199 	/* Start Audio Bus Master 0 */
1200 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD,
1201 	    BMx_CMD_RW | BMx_CMD_BM_CTL_EN);
1202 	return 0;
1203 }
1204 
1205 int
1206 auglx_allocmem(struct auglx_softc *sc, size_t size, size_t align,
1207     struct auglx_dma *p)
1208 {
1209 	int error;
1210 
1211 	p->size = size;
1212 	error = bus_dmamem_alloc(sc->sc_dmat, p->size, align, 0, p->segs, 1,
1213 	    &p->nsegs, BUS_DMA_NOWAIT);
1214 	if (error) {
1215 		DPRINTF(AUGLX_DBG_DMA,
1216 		    ("%s: bus_dmamem_alloc failed: error %d\n",
1217 		    sc->sc_dev.dv_xname, error));
1218 		return error;
1219 	}
1220 
1221 	error = bus_dmamem_map(sc->sc_dmat, p->segs, 1, p->size, &p->addr,
1222 	    BUS_DMA_NOWAIT | sc->sc_dmamap_flags);
1223 	if (error) {
1224 		DPRINTF(AUGLX_DBG_DMA,
1225 		    ("%s: bus_dmamem_map failed: error %d\n",
1226 		    sc->sc_dev.dv_xname, error));
1227 		goto free;
1228 	}
1229 
1230 	error = bus_dmamap_create(sc->sc_dmat, p->size, 1, p->size, 0,
1231 	    BUS_DMA_NOWAIT, &p->map);
1232 	if (error) {
1233 		DPRINTF(AUGLX_DBG_DMA,
1234 		    ("%s: bus_dmamap_create failed: error %d\n",
1235 		    sc->sc_dev.dv_xname, error));
1236 		goto unmap;
1237 	}
1238 
1239 	error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size, NULL,
1240 	    BUS_DMA_NOWAIT);
1241 	if (error) {
1242 		DPRINTF(AUGLX_DBG_DMA,
1243 		    ("%s: bus_dmamap_load failed: error %d\n",
1244 		    sc->sc_dev.dv_xname, error));
1245 		goto destroy;
1246 	}
1247 	return 0;
1248 
1249  destroy:
1250 	bus_dmamap_destroy(sc->sc_dmat, p->map);
1251  unmap:
1252 	bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
1253  free:
1254 	bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
1255 	return error;
1256 }
1257 
1258 void
1259 auglx_freemem(struct auglx_softc *sc, struct auglx_dma *p)
1260 {
1261 	bus_dmamap_unload(sc->sc_dmat, p->map);
1262 	bus_dmamap_destroy(sc->sc_dmat, p->map);
1263 	bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
1264 	bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
1265 }
1266 
1267 void
1268 auglx_get_default_params(void *addr, int mode, struct audio_params *params)
1269 {
1270 	ac97_get_default_params(params);
1271 }
1272 
1273 int
1274 auglx_alloc_prd(struct auglx_softc *sc, size_t size, struct auglx_ring *bm)
1275 {
1276 	int error, rseg;
1277 
1278 	/*
1279 	 * Allocate PRD table structure, and create and load the
1280 	 * DMA map for it.
1281 	 */
1282 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size,
1283 	    PAGE_SIZE, 0, &bm->seg, 1, &rseg, 0)) != 0) {
1284 		printf("%s: unable to allocate PRD, error = %d\n",
1285 		    sc->sc_dev.dv_xname, error);
1286 		goto fail_0;
1287 	}
1288 
1289 	if ((error = bus_dmamem_map(sc->sc_dmat, &bm->seg, rseg,
1290 	    size, (caddr_t *)&bm->sc_vprd,
1291 	    sc->sc_dmamap_flags)) != 0) {
1292 		printf("%s: unable to map PRD, error = %d\n",
1293 		    sc->sc_dev.dv_xname, error);
1294 		goto fail_1;
1295 	}
1296 
1297 	if ((error = bus_dmamap_create(sc->sc_dmat, size,
1298 	    1, size, 0, 0, &bm->sc_prd)) != 0) {
1299 		printf("%s: unable to create PRD DMA map, "
1300 		    "error = %d\n", sc->sc_dev.dv_xname, error);
1301 		goto fail_2;
1302 	}
1303 
1304 	if ((error = bus_dmamap_load(sc->sc_dmat, bm->sc_prd, bm->sc_vprd,
1305 	    size, NULL, 0)) != 0) {
1306 		printf("%s: unable tp load control data DMA map, "
1307 		    "error = %d\n", sc->sc_dev.dv_xname, error);
1308 		goto fail_3;
1309 	}
1310 
1311 	return 0;
1312 
1313  fail_3:
1314 	bus_dmamap_destroy(sc->sc_dmat, bm->sc_prd);
1315  fail_2:
1316 	bus_dmamem_unmap(sc->sc_dmat, (caddr_t)bm->sc_vprd,
1317 	    sizeof(struct auglx_prd));
1318  fail_1:
1319 	bus_dmamem_free(sc->sc_dmat, &bm->seg, rseg);
1320  fail_0:
1321 	return error;
1322 }
1323 
1324 void
1325 auglx_free_prd(struct auglx_softc *sc, struct auglx_ring *bm)
1326 {
1327 	bus_dmamap_unload(sc->sc_dmat, bm->sc_prd);
1328 	bus_dmamap_destroy(sc->sc_dmat, bm->sc_prd);
1329 	bus_dmamem_unmap(sc->sc_dmat, (caddr_t)bm->sc_vprd, bm->sc_size);
1330 	bus_dmamem_free(sc->sc_dmat, &bm->seg, bm->nsegs);
1331 }
1332 
1333 int
1334 auglx_activate(struct device *self, int act)
1335 {
1336 	struct auglx_softc *sc = (struct auglx_softc *)self;
1337 	int rv = 0;
1338 
1339 	switch (act) {
1340 	case DVACT_QUIESCE:
1341 		rv = config_activate_children(self, act);
1342 		break;
1343 	case DVACT_SUSPEND:
1344 		break;
1345 	case DVACT_RESUME:
1346 		ac97_resume(&sc->host_if, sc->codec_if);
1347 		rv = config_activate_children(self, act);
1348 		break;
1349 	case DVACT_DEACTIVATE:
1350 		break;
1351 	}
1352 	return (rv);
1353 }
1354