xref: /openbsd-src/sys/dev/pci/auich.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: auich.c,v 1.35 2003/06/12 18:08:09 mickey Exp $	*/
2 
3 /*
4  * Copyright (c) 2000,2001 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /* #define	AUICH_DEBUG */
30 /*
31  * AC'97 audio found on Intel 810/815/820/440MX chipsets.
32  *	http://developer.intel.com/design/chipsets/datashts/290655.htm
33  *	http://developer.intel.com/design/chipsets/manuals/298028.htm
34  *	http://www.intel.com/design/chipsets/datashts/290716.htm
35  *	http://www.intel.com/design/chipsets/datashts/290744.htm
36  */
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/device.h>
43 
44 #include <dev/pci/pcidevs.h>
45 #include <dev/pci/pcivar.h>
46 
47 #include <sys/audioio.h>
48 #include <dev/audio_if.h>
49 #include <dev/mulaw.h>
50 #include <dev/auconv.h>
51 
52 #include <machine/bus.h>
53 
54 #include <dev/ic/ac97.h>
55 
56 /* 12.1.10 NAMBAR - native audio mixer base address register */
57 #define	AUICH_NAMBAR	0x10
58 /* 12.1.11 NABMBAR - native audio bus mastering base address register */
59 #define	AUICH_NABMBAR	0x14
60 
61 /* table 12-3. native audio bus master control registers */
62 #define	AUICH_BDBAR	0x00	/* 8-byte aligned address */
63 #define	AUICH_CIV		0x04	/* 5 bits current index value */
64 #define	AUICH_LVI		0x05	/* 5 bits last valid index value */
65 #define		AUICH_LVI_MASK	0x1f
66 #define	AUICH_STS		0x06	/* 16 bits status */
67 #define		AUICH_FIFOE	0x10	/* fifo error */
68 #define		AUICH_BCIS	0x08	/* r- buf cmplt int sts; wr ack */
69 #define		AUICH_LVBCI	0x04	/* r- last valid bci, wr ack */
70 #define		AUICH_CELV	0x02	/* current equals last valid */
71 #define		AUICH_DCH		0x01	/* dma halted */
72 #define		AUICH_ISTS_BITS	"\020\01dch\02celv\03lvbci\04bcis\05fifoe"
73 #define	AUICH_PICB	0x08	/* 16 bits */
74 #define	AUICH_PIV		0x0a	/* 5 bits prefetched index value */
75 #define	AUICH_CTRL	0x0b	/* control */
76 #define		AUICH_IOCE	0x10	/* int on completion enable */
77 #define		AUICH_FEIE	0x08	/* fifo error int enable */
78 #define		AUICH_LVBIE	0x04	/* last valid buf int enable */
79 #define		AUICH_RR		0x02	/* 1 - reset regs */
80 #define		AUICH_RPBM	0x01	/* 1 - run, 0 - pause */
81 
82 #define	AUICH_PCMI	0x00
83 #define	AUICH_PCMO	0x10
84 #define	AUICH_MICI	0x20
85 
86 #define	AUICH_GCTRL	0x2c
87 #define		AUICH_SSM_78	0x40000000	/* S/PDIF slots 7 and 8 */
88 #define		AUICH_SSM_69	0x80000000	/* S/PDIF slots 6 and 9 */
89 #define		AUICH_SSM_1011	0xc0000000	/* S/PDIF slots 10 and 11 */
90 #define		AUICH_POM16	0x000000	/* PCM out precision 16bit */
91 #define		AUICH_POM20	0x400000	/* PCM out precision 20bit */
92 #define		AUICH_PCM246_MASK 0x300000
93 #define		AUICH_PCM2	0x000000	/* 2ch output */
94 #define		AUICH_PCM4	0x100000	/* 4ch output */
95 #define		AUICH_PCM6	0x200000	/* 6ch output */
96 #define		AUICH_S2RIE	0x40	/* int when tertiary codec resume */
97 #define		AUICH_SRIE	0x20	/* int when 2ndary codec resume */
98 #define		AUICH_PRIE	0x10	/* int when primary codec resume */
99 #define		AUICH_ACLSO	0x08	/* aclink shut off */
100 #define		AUICH_WRESET	0x04	/* warm reset */
101 #define		AUICH_CRESET	0x02	/* cold reset */
102 #define		AUICH_GIE		0x01	/* gpi int enable */
103 #define	AUICH_GSTS	0x30
104 #define		AUICH_MD3		0x20000	/* pwr-dn semaphore for modem */
105 #define		AUICH_AD3		0x10000	/* pwr-dn semaphore for audio */
106 #define		AUICH_RCS		0x08000	/* read completion status */
107 #define		AUICH_B3S12	0x04000	/* bit 3 of slot 12 */
108 #define		AUICH_B2S12	0x02000	/* bit 2 of slot 12 */
109 #define		AUICH_B1S12	0x01000	/* bit 1 of slot 12 */
110 #define		AUICH_SRI		0x00800	/* secondary resume int */
111 #define		AUICH_PRI		0x00400	/* primary resume int */
112 #define		AUICH_SCR		0x00200	/* secondary codec ready */
113 #define		AUICH_PCR		0x00100	/* primary codec ready */
114 #define		AUICH_MINT	0x00080	/* mic in int */
115 #define		AUICH_POINT	0x00040	/* pcm out int */
116 #define		AUICH_PIINT	0x00020	/* pcm in int */
117 #define		AUICH_MOINT	0x00004	/* modem out int */
118 #define		AUICH_MIINT	0x00002	/* modem in int */
119 #define		AUICH_GSCI	0x00001	/* gpi status change */
120 #define		AUICH_GSTS_BITS	"\020\01gsci\02miict\03moint\06piint\07point\010mint\011pcr\012scr\013pri\014sri\015b1s12\016b2s12\017b3s12\020rcs\021ad3\022md3"
121 #define	AUICH_CAS		0x34	/* 1/8 bit */
122 #define	AUICH_SEMATIMO		1000	/* us */
123 #define	AUICH_RESETIMO		500000	/* us */
124 
125 /*
126  * according to the dev/audiovar.h AU_RING_SIZE is 2^16, what fits
127  * in our limits perfectly, i.e. setting it to higher value
128  * in your kernel config would improve perfomance, still 2^21 is the max
129  */
130 #define	AUICH_DMALIST_MAX	32
131 #define	AUICH_DMASEG_MAX	(65536*2)	/* 64k samples, 2x16 bit samples */
132 struct auich_dmalist {
133 	u_int32_t	base;
134 	u_int32_t	len;
135 #define	AUICH_DMAF_IOC	0x80000000	/* 1-int on complete */
136 #define	AUICH_DMAF_BUP	0x40000000	/* 0-retrans last, 1-transmit 0 */
137 };
138 
139 struct auich_dma {
140 	bus_dmamap_t map;
141 	caddr_t addr;
142 	bus_dma_segment_t segs[AUICH_DMALIST_MAX];
143 	int nsegs;
144 	size_t size;
145 	struct auich_dma *next;
146 };
147 
148 struct auich_softc {
149 	struct device sc_dev;
150 	void *sc_ih;
151 
152 	audio_device_t sc_audev;
153 
154 	bus_space_tag_t iot;
155 	bus_space_handle_t mix_ioh;
156 	bus_space_handle_t aud_ioh;
157 	bus_dma_tag_t dmat;
158 
159 	struct ac97_codec_if *codec_if;
160 	struct ac97_host_if host_if;
161 
162 	/* dma scatter-gather buffer lists, aligned to 8 bytes */
163 	struct auich_dmalist *dmalist_pcmo, *dmap_pcmo,
164 	    dmasto_pcmo[AUICH_DMALIST_MAX+1];
165 	struct auich_dmalist *dmalist_pcmi, *dmap_pcmi,
166 	    dmasto_pcmi[AUICH_DMALIST_MAX+1];;
167 	struct auich_dmalist *dmalist_mici, *dmap_mici,
168 	    dmasto_mici[AUICH_DMALIST_MAX+1];;
169 	/* i/o buffer pointers */
170 	u_int32_t pcmo_start, pcmo_p, pcmo_end;
171 	int pcmo_blksize, pcmo_fifoe;
172 	u_int32_t pcmi_start, pcmi_p, pcmi_end;
173 	int pcmi_blksize, pcmi_fifoe;
174 	u_int32_t mici_start, mici_p, mici_end;
175 	int mici_blksize, mici_fifoe;
176 	struct auich_dma *sc_dmas;
177 
178 	void (*sc_pintr)(void *);
179 	void *sc_parg;
180 
181 	void (*sc_rintr)(void *);
182 	void *sc_rarg;
183 
184 	void *powerhook;
185 	int suspend;
186 	u_int16_t ext_ctrl;
187 	int sc_sample_size;
188 	int sc_sts_reg;
189 	int sc_ignore_codecready;
190 	int flags;
191 };
192 
193 #ifdef AUICH_DEBUG
194 #define	DPRINTF(l,x)	do { if (auich_debug & (l)) printf x; } while(0)
195 int auich_debug = 0xfffe;
196 #define	AUICH_DEBUG_CODECIO	0x0001
197 #define	AUICH_DEBUG_DMA		0x0002
198 #define	AUICH_DEBUG_PARAM	0x0004
199 #else
200 #define	DPRINTF(x,y)	/* nothing */
201 #endif
202 
203 struct cfdriver	auich_cd = {
204 	NULL, "auich", DV_DULL
205 };
206 
207 int  auich_match(struct device *, void *, void *);
208 void auich_attach(struct device *, struct device *, void *);
209 int  auich_intr(void *);
210 
211 struct cfattach auich_ca = {
212 	sizeof(struct auich_softc), auich_match, auich_attach
213 };
214 
215 static const struct auich_devtype {
216 	int	vendor;
217 	int	product;
218 	int	options;
219 	char	name[8];
220 } auich_devices[] = {
221 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801AA_ACA,	0, "ICH" },
222 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801AB_ACA,	0, "ICH0" },
223 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801BA_ACA,	0, "ICH2" },
224 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801CA_ACA,	0, "ICH3" },
225 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801DB_ACA,	0, "ICH4" },
226 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801EB_ACA,	0, "ICH5" },
227 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82440MX_ACA,	0, "440MX" },
228 	{ PCI_VENDOR_SIS,	PCI_PRODUCT_SIS_7012_ACA,	0, "SiS7012" },
229 	{ PCI_VENDOR_NVIDIA,	PCI_PRODUCT_NVIDIA_NFORCE_ACA,	0, "nForce" },
230 	{ PCI_VENDOR_NVIDIA,	PCI_PRODUCT_NVIDIA_NFORCE2_ACA,	0, "nForce2" },
231 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_PBC768_ACA,	0, "AMD768" },
232 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_8111_ACA,	0, "AMD8111" },
233 };
234 
235 int auich_open(void *, int);
236 void auich_close(void *);
237 int auich_query_encoding(void *, struct audio_encoding *);
238 int auich_set_params(void *, int, int, struct audio_params *,
239     struct audio_params *);
240 int auich_round_blocksize(void *, int);
241 int auich_halt_output(void *);
242 int auich_halt_input(void *);
243 int auich_getdev(void *, struct audio_device *);
244 int auich_set_port(void *, mixer_ctrl_t *);
245 int auich_get_port(void *, mixer_ctrl_t *);
246 int auich_query_devinfo(void *, mixer_devinfo_t *);
247 void *auich_allocm(void *, int, size_t, int, int);
248 void auich_freem(void *, void *, int);
249 size_t auich_round_buffersize(void *, int, size_t);
250 paddr_t auich_mappage(void *, void *, off_t, int);
251 int auich_get_props(void *);
252 int auich_trigger_output(void *, void *, void *, int, void (*)(void *),
253     void *, struct audio_params *);
254 int auich_trigger_input(void *, void *, void *, int, void (*)(void *),
255     void *, struct audio_params *);
256 
257 void auich_powerhook(int, void *);
258 
259 struct audio_hw_if auich_hw_if = {
260 	auich_open,
261 	auich_close,
262 	NULL,			/* drain */
263 	auich_query_encoding,
264 	auich_set_params,
265 	auich_round_blocksize,
266 	NULL,			/* commit_setting */
267 	NULL,			/* init_output */
268 	NULL,			/* init_input */
269 	NULL,			/* start_output */
270 	NULL,			/* start_input */
271 	auich_halt_output,
272 	auich_halt_input,
273 	NULL,			/* speaker_ctl */
274 	auich_getdev,
275 	NULL,			/* getfd */
276 	auich_set_port,
277 	auich_get_port,
278 	auich_query_devinfo,
279 	auich_allocm,
280 	auich_freem,
281 	auich_round_buffersize,
282 	auich_mappage,
283 	auich_get_props,
284 	auich_trigger_output,
285 	auich_trigger_input
286 };
287 
288 int  auich_attach_codec(void *, struct ac97_codec_if *);
289 int  auich_read_codec(void *, u_int8_t, u_int16_t *);
290 int  auich_write_codec(void *, u_int8_t, u_int16_t);
291 void auich_reset_codec(void *);
292 enum ac97_host_flags auich_flags_codec(void *);
293 
294 int
295 auich_match(parent, match, aux)
296 	struct device *parent;
297 	void *match;
298 	void *aux;
299 {
300 	struct pci_attach_args *pa = aux;
301 	int i;
302 
303 	for (i = sizeof(auich_devices)/sizeof(auich_devices[0]); i--;)
304 		if (PCI_VENDOR(pa->pa_id) == auich_devices[i].vendor &&
305 		    PCI_PRODUCT(pa->pa_id) == auich_devices[i].product)
306 			return 1;
307 
308 	return 0;
309 }
310 
311 void
312 auich_attach(parent, self, aux)
313 	struct device *parent, *self;
314 	void *aux;
315 {
316 	struct auich_softc *sc = (struct auich_softc *)self;
317 	struct pci_attach_args *pa = aux;
318 	pci_intr_handle_t ih;
319 	bus_size_t mix_size, aud_size;
320 	pcireg_t csr;
321 	const char *intrstr;
322 	u_int32_t status;
323 	int i;
324 
325 	/* SiS 7012 needs special handling */
326 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SIS &&
327 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SIS_7012_ACA) {
328 		sc->sc_sts_reg = AUICH_PICB;
329 		sc->sc_sample_size = 1;
330 	} else {
331 		sc->sc_sts_reg = AUICH_STS;
332 		sc->sc_sample_size = 2;
333 	}
334 
335 	if (pci_mapreg_map(pa, AUICH_NAMBAR, PCI_MAPREG_TYPE_IO, 0,
336 			   &sc->iot, &sc->mix_ioh, NULL, &mix_size, 0)) {
337 		printf(": can't map codec i/o space\n");
338 		return;
339 	}
340 	if (pci_mapreg_map(pa, AUICH_NABMBAR, PCI_MAPREG_TYPE_IO, 0,
341 			   &sc->iot, &sc->aud_ioh, NULL, &aud_size, 0)) {
342 		printf(": can't map device i/o space\n");
343 		bus_space_unmap(sc->iot, sc->mix_ioh, mix_size);
344 		return;
345 	}
346 	sc->dmat = pa->pa_dmat;
347 
348 	/* enable bus mastering (should not it be mi?) */
349 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
350 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
351 	    csr | PCI_COMMAND_MASTER_ENABLE);
352 
353 	if (pci_intr_map(pa, &ih)) {
354 		printf(": can't map interrupt\n");
355 		bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
356 		bus_space_unmap(sc->iot, sc->mix_ioh, mix_size);
357 		return;
358 	}
359 	intrstr = pci_intr_string(pa->pa_pc, ih);
360 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, auich_intr,
361 				       sc, sc->sc_dev.dv_xname);
362 	if (!sc->sc_ih) {
363 		printf(": can't establish interrupt");
364 		if (intrstr)
365 			printf(" at %s", intrstr);
366 		printf("\n");
367 		bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
368 		bus_space_unmap(sc->iot, sc->mix_ioh, mix_size);
369 		return;
370 	}
371 
372 	for (i = sizeof(auich_devices)/sizeof(auich_devices[0]); i--;)
373 		if (PCI_PRODUCT(pa->pa_id) == auich_devices[i].product)
374 			break;
375 
376 	snprintf(sc->sc_audev.name, sizeof sc->sc_audev.name, "%s AC97",
377 		 auich_devices[i].name);
378 	snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version, "0x%02x",
379 		 PCI_REVISION(pa->pa_class));
380 	strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname,
381 		sizeof sc->sc_audev.config);
382 
383 	printf(": %s, %s\n", intrstr, sc->sc_audev.name);
384 
385 	/* allocate dma lists */
386 #define	a(a)	(void *)(((u_long)(a) + sizeof(*(a)) - 1) & ~(sizeof(*(a))-1))
387 	sc->dmalist_pcmo = sc->dmap_pcmo = a(sc->dmasto_pcmo);
388 	sc->dmalist_pcmi = sc->dmap_pcmi = a(sc->dmasto_pcmi);
389 	sc->dmalist_mici = sc->dmap_mici = a(sc->dmasto_mici);
390 #undef a
391 	DPRINTF(AUICH_DEBUG_DMA, ("auich_attach: lists %p %p %p\n",
392 	    sc->dmalist_pcmo, sc->dmalist_pcmi, sc->dmalist_mici));
393 
394 	/* Reset codec and AC'97 */
395 	auich_reset_codec(sc);
396 	status = bus_space_read_4(sc->iot, sc->aud_ioh, AUICH_GSTS);
397 	if (!(status & AUICH_PCR)) {	/* reset failure */
398 		if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL &&
399 		    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801DB_ACA) {
400 			/* MSI 845G Max never return AUICH_PCR */
401 			sc->sc_ignore_codecready = 1;
402 		} else
403 			return;
404 	}
405 
406 	sc->host_if.arg = sc;
407 	sc->host_if.attach = auich_attach_codec;
408 	sc->host_if.read = auich_read_codec;
409 	sc->host_if.write = auich_write_codec;
410 	sc->host_if.reset = auich_reset_codec;
411 	sc->host_if.flags = auich_flags_codec;
412 	if (sc->sc_dev.dv_cfdata->cf_flags & 0x0001)
413 		sc->flags = AC97_HOST_SWAPPED_CHANNELS;
414 
415 	if (ac97_attach(&sc->host_if) != 0) {
416 		pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
417 		bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
418 		bus_space_unmap(sc->iot, sc->mix_ioh, mix_size);
419 		return;
420 	}
421 
422 	audio_attach_mi(&auich_hw_if, sc, &sc->sc_dev);
423 
424 	/* Watch for power changes */
425 	sc->suspend = PWR_RESUME;
426 	sc->powerhook = powerhook_establish(auich_powerhook, sc);
427 }
428 
429 int
430 auich_read_codec(v, reg, val)
431 	void *v;
432 	u_int8_t reg;
433 	u_int16_t *val;
434 {
435 	struct auich_softc *sc = v;
436 	int i;
437 
438 	/* wait for an access semaphore */
439 	for (i = AUICH_SEMATIMO; i-- &&
440 	    bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_CAS) & 1; DELAY(1));
441 
442 	if (!sc->sc_ignore_codecready && i < 0) {
443 		DPRINTF(AUICH_DEBUG_CODECIO,
444 		    ("%s: read_codec timeout\n", sc->sc_dev.dv_xname));
445 		return (-1);
446 	}
447 
448 	*val = bus_space_read_2(sc->iot, sc->mix_ioh, reg);
449 	DPRINTF(AUICH_DEBUG_CODECIO, ("%s: read_codec(%x, %x)\n",
450 	    sc->sc_dev.dv_xname, reg, *val));
451 	return (0);
452 }
453 
454 int
455 auich_write_codec(v, reg, val)
456 	void *v;
457 	u_int8_t reg;
458 	u_int16_t val;
459 {
460 	struct auich_softc *sc = v;
461 	int i;
462 
463 	/* wait for an access semaphore */
464 	for (i = AUICH_SEMATIMO; i-- &&
465 	    bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_CAS) & 1; DELAY(1));
466 
467 	if (sc->sc_ignore_codecready || i >= 0) {
468 		DPRINTF(AUICH_DEBUG_CODECIO, ("%s: write_codec(%x, %x)\n",
469 		    sc->sc_dev.dv_xname, reg, val));
470 		bus_space_write_2(sc->iot, sc->mix_ioh, reg, val);
471 		return (0);
472 	} else {
473 		DPRINTF(AUICH_DEBUG_CODECIO,
474 		    ("%s: write_codec timeout\n", sc->sc_dev.dv_xname));
475 		return (-1);
476 	}
477 }
478 
479 int
480 auich_attach_codec(v, cif)
481 	void *v;
482 	struct ac97_codec_if *cif;
483 {
484 	struct auich_softc *sc = v;
485 
486 	sc->codec_if = cif;
487 	return 0;
488 }
489 
490 void
491 auich_reset_codec(v)
492 	void *v;
493 {
494 	struct auich_softc *sc = v;
495 	u_int32_t control;
496 	int i;
497 
498 	control = bus_space_read_4(sc->iot, sc->aud_ioh, AUICH_GCTRL);
499 	control &= ~(AUICH_ACLSO | AUICH_PCM246_MASK);
500 	control |= (control & AUICH_CRESET) ? AUICH_WRESET : AUICH_CRESET;
501 	bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_GCTRL, AUICH_CRESET);
502 
503 	for (i = AUICH_RESETIMO; i-- &&
504 	    !(bus_space_read_4(sc->iot, sc->aud_ioh, AUICH_GSTS) & AUICH_PCR);
505 	    DELAY(1));
506 
507 	if (i < 0)
508 		DPRINTF(AUICH_DEBUG_CODECIO,
509 		    ("%s: reset_codec timeout\n", sc->sc_dev.dv_xname));
510 }
511 
512 enum ac97_host_flags
513 auich_flags_codec(void *v)
514 {
515 	struct auich_softc *sc = v;
516 
517 	return (sc->flags);
518 }
519 
520 int
521 auich_open(v, flags)
522 	void *v;
523 	int flags;
524 {
525 	return 0;
526 }
527 
528 void
529 auich_close(v)
530 	void *v;
531 {
532 }
533 
534 int
535 auich_query_encoding(v, aep)
536 	void *v;
537 	struct audio_encoding *aep;
538 {
539 	switch (aep->index) {
540 	case 0:
541 		strlcpy(aep->name, AudioEulinear, sizeof aep->name);
542 		aep->encoding = AUDIO_ENCODING_ULINEAR;
543 		aep->precision = 8;
544 		aep->flags = 0;
545 		return (0);
546 	case 1:
547 		strlcpy(aep->name, AudioEmulaw, sizeof aep->name);
548 		aep->encoding = AUDIO_ENCODING_ULAW;
549 		aep->precision = 8;
550 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
551 		return (0);
552 	case 2:
553 		strlcpy(aep->name, AudioEalaw, sizeof aep->name);
554 		aep->encoding = AUDIO_ENCODING_ALAW;
555 		aep->precision = 8;
556 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
557 		return (0);
558 	case 3:
559 		strlcpy(aep->name, AudioEslinear, sizeof aep->name);
560 		aep->encoding = AUDIO_ENCODING_SLINEAR;
561 		aep->precision = 8;
562 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
563 		return (0);
564 	case 4:
565 		strlcpy(aep->name, AudioEslinear_le, sizeof aep->name);
566 		aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
567 		aep->precision = 16;
568 		aep->flags = 0;
569 		return (0);
570 	case 5:
571 		strlcpy(aep->name, AudioEulinear_le, sizeof aep->name);
572 		aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
573 		aep->precision = 16;
574 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
575 		return (0);
576 	case 6:
577 		strlcpy(aep->name, AudioEslinear_be, sizeof aep->name);
578 		aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
579 		aep->precision = 16;
580 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
581 		return (0);
582 	case 7:
583 		strlcpy(aep->name, AudioEulinear_be, sizeof aep->name);
584 		aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
585 		aep->precision = 16;
586 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
587 		return (0);
588 	default:
589 		return (EINVAL);
590 	}
591 }
592 
593 int
594 auich_set_params(v, setmode, usemode, play, rec)
595 	void *v;
596 	int setmode, usemode;
597 	struct audio_params *play, *rec;
598 {
599 	struct auich_softc *sc = v;
600 	int error;
601 
602 	if (setmode & AUMODE_PLAY) {
603 		play->factor = 1;
604 		play->sw_code = NULL;
605 		switch(play->encoding) {
606 		case AUDIO_ENCODING_ULAW:
607 			switch (play->channels) {
608 			case 1:
609 				play->factor = 4;
610 				play->sw_code = mulaw_to_slinear16_mts;
611 				break;
612 			case 2:
613 				play->factor = 2;
614 				play->sw_code = mulaw_to_slinear16;
615 				break;
616 			default:
617 				return (EINVAL);
618 			}
619 			break;
620 		case AUDIO_ENCODING_SLINEAR_LE:
621 			switch (play->precision) {
622 			case 8:
623 				switch (play->channels) {
624 				case 1:
625 					play->factor = 4;
626 					play->sw_code = linear8_to_linear16_mts;
627 					break;
628 				case 2:
629 					play->factor = 2;
630 					play->sw_code = linear8_to_linear16;
631 					break;
632 				default:
633 					return (EINVAL);
634 				}
635 				break;
636 			case 16:
637 				switch (play->channels) {
638 				case 1:
639 					play->factor = 2;
640 					play->sw_code = noswap_bytes_mts;
641 					break;
642 				case 2:
643 					break;
644 				default:
645 					return (EINVAL);
646 				}
647 				break;
648 			default:
649 				return (EINVAL);
650 			}
651 			break;
652 		case AUDIO_ENCODING_ULINEAR_LE:
653 			switch (play->precision) {
654 			case 8:
655 				switch (play->channels) {
656 				case 1:
657 					play->factor = 4;
658 					play->sw_code = ulinear8_to_linear16_mts;
659 					break;
660 				case 2:
661 					play->factor = 2;
662 					play->sw_code = ulinear8_to_linear16;
663 					break;
664 				default:
665 					return (EINVAL);
666 				}
667 				break;
668 			case 16:
669 				switch (play->channels) {
670 				case 1:
671 					play->factor = 2;
672 					play->sw_code = change_sign16_mts;
673 					break;
674 				case 2:
675 					play->sw_code = change_sign16;
676 					break;
677 				default:
678 					return (EINVAL);
679 				}
680 				break;
681 			default:
682 				return (EINVAL);
683 			}
684 			break;
685 		case AUDIO_ENCODING_ALAW:
686 			switch (play->channels) {
687 			case 1:
688 				play->factor = 4;
689 				play->sw_code = alaw_to_slinear16_mts;
690 			case 2:
691 				play->factor = 2;
692 				play->sw_code = alaw_to_slinear16;
693 			default:
694 				return (EINVAL);
695 			}
696 			break;
697 		case AUDIO_ENCODING_SLINEAR_BE:
698 			switch (play->precision) {
699 			case 8:
700 				switch (play->channels) {
701 				case 1:
702 					play->factor = 4;
703 					play->sw_code = linear8_to_linear16_mts;
704 					break;
705 				case 2:
706 					play->factor = 2;
707 					play->sw_code = linear8_to_linear16;
708 					break;
709 				default:
710 					return (EINVAL);
711 				}
712 				break;
713 			case 16:
714 				switch (play->channels) {
715 				case 1:
716 					play->factor = 2;
717 					play->sw_code = swap_bytes_mts;
718 					break;
719 				case 2:
720 					play->sw_code = swap_bytes;
721 					break;
722 				default:
723 					return (EINVAL);
724 				}
725 				break;
726 			default:
727 				return (EINVAL);
728 			}
729 			break;
730 		case AUDIO_ENCODING_ULINEAR_BE:
731 			switch (play->precision) {
732 			case 8:
733 				switch (play->channels) {
734 				case 1:
735 					play->factor = 4;
736 					play->sw_code = ulinear8_to_linear16_mts;
737 					break;
738 				case 2:
739 					play->factor = 2;
740 					play->sw_code = ulinear8_to_linear16;
741 					break;
742 				default:
743 					return (EINVAL);
744 				}
745 				break;
746 			case 16:
747 				switch (play->channels) {
748 				case 1:
749 					play->factor = 2;
750 					play->sw_code = change_sign16_swap_bytes_mts;
751 					break;
752 				case 2:
753 					play->sw_code = change_sign16_swap_bytes;
754 					break;
755 				default:
756 					return (EINVAL);
757 				}
758 				break;
759 			default:
760 				return (EINVAL);
761 			}
762 			break;
763 		default:
764 			return (EINVAL);
765 		}
766 
767 		if ((error = ac97_set_rate(sc->codec_if, play, AUMODE_PLAY)))
768 			return (error);
769 	}
770 
771 	if (setmode & AUMODE_RECORD) {
772 		rec->factor = 1;
773 		rec->sw_code = 0;
774 		switch(rec->encoding) {
775 		case AUDIO_ENCODING_ULAW:
776 			rec->sw_code = ulinear8_to_mulaw;
777 			break;
778 		case AUDIO_ENCODING_SLINEAR_LE:
779 			if (rec->precision == 8)
780 				rec->sw_code = change_sign8;
781 			break;
782 		case AUDIO_ENCODING_ULINEAR_LE:
783 			if (rec->precision == 16)
784 				rec->sw_code = change_sign16;
785 			break;
786 		case AUDIO_ENCODING_ALAW:
787 			rec->sw_code = ulinear8_to_alaw;
788 			break;
789 		case AUDIO_ENCODING_SLINEAR_BE:
790 			if (rec->precision == 16)
791 				rec->sw_code = swap_bytes;
792 			else
793 				rec->sw_code = change_sign8;
794 			break;
795 		case AUDIO_ENCODING_ULINEAR_BE:
796 			if (rec->precision == 16)
797 				rec->sw_code = swap_bytes_change_sign16;
798 			break;
799 		default:
800 			return (EINVAL);
801 		}
802 
803 		if ((error = ac97_set_rate(sc->codec_if, rec, AUMODE_RECORD)))
804 			return (error);
805 	}
806 
807 	return (0);
808 }
809 
810 int
811 auich_round_blocksize(v, blk)
812 	void *v;
813 	int blk;
814 {
815 	return blk & ~0x3f;
816 }
817 
818 int
819 auich_halt_output(v)
820 	void *v;
821 {
822 	struct auich_softc *sc = v;
823 
824 	DPRINTF(AUICH_DEBUG_DMA, ("%s: halt_output\n", sc->sc_dev.dv_xname));
825 
826 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CTRL, AUICH_RR);
827 
828 	return 0;
829 }
830 
831 int
832 auich_halt_input(v)
833 	void *v;
834 {
835 	struct auich_softc *sc = v;
836 
837 	DPRINTF(AUICH_DEBUG_DMA,
838 	    ("%s: halt_input\n", sc->sc_dev.dv_xname));
839 
840 	/* XXX halt both unless known otherwise */
841 
842 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL, AUICH_RR);
843 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_MICI + AUICH_CTRL, AUICH_RR);
844 
845 	return 0;
846 }
847 
848 int
849 auich_getdev(v, adp)
850 	void *v;
851 	struct audio_device *adp;
852 {
853 	struct auich_softc *sc = v;
854 	*adp = sc->sc_audev;
855 	return 0;
856 }
857 
858 int
859 auich_set_port(v, cp)
860 	void *v;
861 	mixer_ctrl_t *cp;
862 {
863 	struct auich_softc *sc = v;
864 	return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
865 }
866 
867 int
868 auich_get_port(v, cp)
869 	void *v;
870 	mixer_ctrl_t *cp;
871 {
872 	struct auich_softc *sc = v;
873 	return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
874 }
875 
876 int
877 auich_query_devinfo(v, dp)
878 	void *v;
879 	mixer_devinfo_t *dp;
880 {
881 	struct auich_softc *sc = v;
882 	return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp);
883 }
884 
885 void *
886 auich_allocm(v, direction, size, pool, flags)
887 	void *v;
888 	int direction;
889 	size_t size;
890 	int pool, flags;
891 {
892 	struct auich_softc *sc = v;
893 	struct auich_dma *p;
894 	int error;
895 
896 	if (size > AUICH_DMALIST_MAX * AUICH_DMASEG_MAX)
897 		return NULL;
898 
899 	p = malloc(sizeof(*p), pool, flags);
900 	if (!p)
901 		return NULL;
902 	bzero(p, sizeof(*p));
903 
904 	p->size = size;
905 	if ((error = bus_dmamem_alloc(sc->dmat, p->size, NBPG, 0, p->segs,
906 	    1, &p->nsegs, BUS_DMA_NOWAIT)) != 0) {
907 		printf("%s: unable to allocate dma, error = %d\n",
908 		    sc->sc_dev.dv_xname, error);
909 		free(p, pool);
910 		return NULL;
911 	}
912 
913 	if ((error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size,
914 	    &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
915 		printf("%s: unable to map dma, error = %d\n",
916 		    sc->sc_dev.dv_xname, error);
917 		bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
918 		free(p, pool);
919 		return NULL;
920 	}
921 
922 	if ((error = bus_dmamap_create(sc->dmat, p->size, 1,
923 	    p->size, 0, BUS_DMA_NOWAIT, &p->map)) != 0) {
924 		printf("%s: unable to create dma map, error = %d\n",
925 		    sc->sc_dev.dv_xname, error);
926 		bus_dmamem_unmap(sc->dmat, p->addr, size);
927 		bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
928 		free(p, pool);
929 		return NULL;
930 	}
931 
932 	if ((error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size,
933 	    NULL, BUS_DMA_NOWAIT)) != 0) {
934 		printf("%s: unable to load dma map, error = %d\n",
935 		    sc->sc_dev.dv_xname, error);
936 		bus_dmamap_destroy(sc->dmat, p->map);
937 		bus_dmamem_unmap(sc->dmat, p->addr, size);
938 		bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
939 		free(p, pool);
940 		return NULL;
941 	}
942 
943 	p->next = sc->sc_dmas;
944 	sc->sc_dmas = p;
945 
946 	return p->addr;
947 }
948 
949 void
950 auich_freem(v, ptr, pool)
951 	void *v;
952 	void *ptr;
953 	int pool;
954 {
955 	struct auich_softc *sc = v;
956 	struct auich_dma *p;
957 
958 	for (p = sc->sc_dmas; p->addr != ptr; p = p->next)
959 		if (p->next == NULL) {
960 			printf("auich_freem: trying to free not allocated memory");
961 			return;
962 		}
963 
964 	bus_dmamap_unload(sc->dmat, p->map);
965 	bus_dmamap_destroy(sc->dmat, p->map);
966 	bus_dmamem_unmap(sc->dmat, p->addr, p->size);
967 	bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
968 	free(p, pool);
969 }
970 
971 size_t
972 auich_round_buffersize(v, direction, size)
973 	void *v;
974 	int direction;
975 	size_t size;
976 {
977 	if (size > AUICH_DMALIST_MAX * AUICH_DMASEG_MAX)
978 		size = AUICH_DMALIST_MAX * AUICH_DMASEG_MAX;
979 
980 	return size;
981 }
982 
983 paddr_t
984 auich_mappage(v, mem, off, prot)
985 	void *v;
986 	void *mem;
987 	off_t off;
988 	int prot;
989 {
990 	struct auich_softc *sc = v;
991 	struct auich_dma *p;
992 
993 	if (off < 0)
994 		return -1;
995 
996 	for (p = sc->sc_dmas; p && p->addr != mem; p = p->next);
997 	if (!p)
998 		return -1;
999 
1000 	return bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs,
1001 	    off, prot, BUS_DMA_WAITOK);
1002 }
1003 
1004 int
1005 auich_get_props(v)
1006 	void *v;
1007 {
1008 	return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
1009 }
1010 
1011 int
1012 auich_intr(v)
1013 	void *v;
1014 {
1015 	struct auich_softc *sc = v;
1016 	int ret = 0, sts, gsts, i;
1017 
1018 	gsts = bus_space_read_2(sc->iot, sc->aud_ioh, AUICH_GSTS);
1019 	DPRINTF(AUICH_DEBUG_DMA, ("auich_intr: gsts=%b\n", gsts, AUICH_GSTS_BITS));
1020 
1021 	if (gsts & AUICH_POINT) {
1022 		sts = bus_space_read_2(sc->iot, sc->aud_ioh,
1023 		    AUICH_PCMO + sc->sc_sts_reg);
1024 		DPRINTF(AUICH_DEBUG_DMA,
1025 		    ("auich_intr: osts=%b\n", sts, AUICH_ISTS_BITS));
1026 
1027 		if (sts & AUICH_FIFOE) {
1028 			printf("%s: fifo underrun # %u\n",
1029 			    sc->sc_dev.dv_xname, ++sc->pcmo_fifoe);
1030 		}
1031 
1032 		i = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CIV);
1033 		if (sts & (AUICH_LVBCI | AUICH_CELV)) {
1034 			struct auich_dmalist *q, *qe;
1035 
1036 			q = sc->dmap_pcmo;
1037 			qe = &sc->dmalist_pcmo[i];
1038 
1039 			while (q != qe) {
1040 
1041 				q->base = sc->pcmo_p;
1042 				q->len = (sc->pcmo_blksize /
1043 				    sc->sc_sample_size) | AUICH_DMAF_IOC;
1044 				DPRINTF(AUICH_DEBUG_DMA,
1045 				    ("auich_intr: %p, %p = %x @ %p\n",
1046 				    qe, q, sc->pcmo_blksize /
1047 				    sc->sc_sample_size, sc->pcmo_p));
1048 
1049 				sc->pcmo_p += sc->pcmo_blksize;
1050 				if (sc->pcmo_p >= sc->pcmo_end)
1051 					sc->pcmo_p = sc->pcmo_start;
1052 
1053 				if (++q == &sc->dmalist_pcmo[AUICH_DMALIST_MAX])
1054 					q = sc->dmalist_pcmo;
1055 			}
1056 
1057 			sc->dmap_pcmo = q;
1058 			bus_space_write_1(sc->iot, sc->aud_ioh,
1059 			    AUICH_PCMO + AUICH_LVI,
1060 			    (sc->dmap_pcmo - sc->dmalist_pcmo - 1) &
1061 			    AUICH_LVI_MASK);
1062 		}
1063 
1064 		if (sts & AUICH_BCIS && sc->sc_pintr)
1065 			sc->sc_pintr(sc->sc_parg);
1066 
1067 		/* int ack */
1068 		bus_space_write_2(sc->iot, sc->aud_ioh,
1069 		    AUICH_PCMO + sc->sc_sts_reg, sts &
1070 		    (AUICH_LVBCI | AUICH_CELV | AUICH_BCIS | AUICH_FIFOE));
1071 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_POINT);
1072 		ret++;
1073 	}
1074 
1075 	if (gsts & AUICH_PIINT) {
1076 		sts = bus_space_read_2(sc->iot, sc->aud_ioh,
1077 		    AUICH_PCMI + sc->sc_sts_reg);
1078 		DPRINTF(AUICH_DEBUG_DMA,
1079 		    ("auich_intr: ists=%b\n", sts, AUICH_ISTS_BITS));
1080 
1081 		if (sts & AUICH_FIFOE) {
1082 			printf("%s: in fifo overrun # %u\n",
1083 			    sc->sc_dev.dv_xname, ++sc->pcmi_fifoe);
1084 		}
1085 
1086 		i = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CIV);
1087 		if (sts & (AUICH_LVBCI | AUICH_CELV)) {
1088 			struct auich_dmalist *q, *qe;
1089 
1090 			q = sc->dmap_pcmi;
1091 			qe = &sc->dmalist_pcmi[i];
1092 
1093 			while (q != qe) {
1094 
1095 				q->base = sc->pcmi_p;
1096 				q->len = (sc->pcmi_blksize /
1097 				    sc->sc_sample_size) | AUICH_DMAF_IOC;
1098 				DPRINTF(AUICH_DEBUG_DMA,
1099 				    ("auich_intr: %p, %p = %x @ %p\n",
1100 				    qe, q, sc->pcmi_blksize /
1101 				    sc->sc_sample_size, sc->pcmi_p));
1102 
1103 				sc->pcmi_p += sc->pcmi_blksize;
1104 				if (sc->pcmi_p >= sc->pcmi_end)
1105 					sc->pcmi_p = sc->pcmi_start;
1106 
1107 				if (++q == &sc->dmalist_pcmi[AUICH_DMALIST_MAX])
1108 					q = sc->dmalist_pcmi;
1109 			}
1110 
1111 			sc->dmap_pcmi = q;
1112 			bus_space_write_1(sc->iot, sc->aud_ioh,
1113 			    AUICH_PCMI + AUICH_LVI,
1114 			    (sc->dmap_pcmi - sc->dmalist_pcmi - 1) &
1115 			    AUICH_LVI_MASK);
1116 		}
1117 
1118 		if (sts & AUICH_BCIS && sc->sc_rintr)
1119 			sc->sc_rintr(sc->sc_rarg);
1120 
1121 		/* int ack */
1122 		bus_space_write_2(sc->iot, sc->aud_ioh,
1123 		    AUICH_PCMI + sc->sc_sts_reg, sts &
1124 		    (AUICH_LVBCI | AUICH_CELV | AUICH_BCIS | AUICH_FIFOE));
1125 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_POINT);
1126 		ret++;
1127 	}
1128 
1129 	if (gsts & AUICH_MIINT) {
1130 		sts = bus_space_read_2(sc->iot, sc->aud_ioh,
1131 		    AUICH_MICI + sc->sc_sts_reg);
1132 		DPRINTF(AUICH_DEBUG_DMA,
1133 		    ("auich_intr: ists=%b\n", sts, AUICH_ISTS_BITS));
1134 		if (sts & AUICH_FIFOE)
1135 			printf("%s: mic fifo overrun\n", sc->sc_dev.dv_xname);
1136 
1137 		/* TODO mic input dma */
1138 
1139 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_MIINT);
1140 	}
1141 
1142 	return ret;
1143 }
1144 
1145 int
1146 auich_trigger_output(v, start, end, blksize, intr, arg, param)
1147 	void *v;
1148 	void *start, *end;
1149 	int blksize;
1150 	void (*intr)(void *);
1151 	void *arg;
1152 	struct audio_params *param;
1153 {
1154 	struct auich_softc *sc = v;
1155 	struct auich_dmalist *q;
1156 	struct auich_dma *p;
1157 
1158 	DPRINTF(AUICH_DEBUG_DMA,
1159 	    ("auich_trigger_output(%x, %x, %d, %p, %p, %p)\n",
1160 	    start, end, blksize, intr, arg, param));
1161 
1162 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1163 	if (!p)
1164 		return -1;
1165 
1166 	sc->sc_pintr = intr;
1167 	sc->sc_parg = arg;
1168 
1169 	/*
1170 	 * The logic behind this is:
1171 	 * setup one buffer to play, then LVI dump out the rest
1172 	 * to the scatter-gather chain.
1173 	 */
1174 	sc->pcmo_start = p->segs->ds_addr;
1175 	sc->pcmo_p = sc->pcmo_start + blksize;
1176 	sc->pcmo_end = sc->pcmo_start + (end - start);
1177 	sc->pcmo_blksize = blksize;
1178 
1179 	q = sc->dmap_pcmo = sc->dmalist_pcmo;
1180 	q->base = sc->pcmo_start;
1181 	q->len = (blksize / sc->sc_sample_size) | AUICH_DMAF_IOC;
1182 	if (++q == &sc->dmalist_pcmo[AUICH_DMALIST_MAX])
1183 		q = sc->dmalist_pcmo;
1184 	sc->dmap_pcmo = q;
1185 
1186 	bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_BDBAR,
1187 	    kvtop((caddr_t)sc->dmalist_pcmo));
1188 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CTRL,
1189 	    AUICH_IOCE | AUICH_FEIE | AUICH_LVBIE | AUICH_RPBM);
1190 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_LVI,
1191 	    (sc->dmap_pcmo - 1 - sc->dmalist_pcmo) & AUICH_LVI_MASK);
1192 
1193 	return 0;
1194 }
1195 
1196 int
1197 auich_trigger_input(v, start, end, blksize, intr, arg, param)
1198 	void *v;
1199 	void *start, *end;
1200 	int blksize;
1201 	void (*intr)(void *);
1202 	void *arg;
1203 	struct audio_params *param;
1204 {
1205 	struct auich_softc *sc = v;
1206 	struct auich_dmalist *q;
1207 	struct auich_dma *p;
1208 
1209 	DPRINTF(AUICH_DEBUG_DMA,
1210 	    ("auich_trigger_input(%x, %x, %d, %p, %p, %p)\n",
1211 	    start, end, blksize, intr, arg, param));
1212 
1213 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1214 	if (!p)
1215 		return -1;
1216 
1217 	sc->sc_rintr = intr;
1218 	sc->sc_rarg = arg;
1219 
1220 	/*
1221 	 * The logic behind this is:
1222 	 * setup one buffer to play, then LVI dump out the rest
1223 	 * to the scatter-gather chain.
1224 	 */
1225 	sc->pcmi_start = p->segs->ds_addr;
1226 	sc->pcmi_p = sc->pcmi_start + blksize;
1227 	sc->pcmi_end = sc->pcmi_start + (end - start);
1228 	sc->pcmi_blksize = blksize;
1229 
1230 	q = sc->dmap_pcmi = sc->dmalist_pcmi;
1231 	q->base = sc->pcmi_start;
1232 	q->len = (blksize / sc->sc_sample_size) | AUICH_DMAF_IOC;
1233 	if (++q == &sc->dmalist_pcmi[AUICH_DMALIST_MAX])
1234 		q = sc->dmalist_pcmi;
1235 	sc->dmap_pcmi = q;
1236 
1237 	bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_BDBAR,
1238 	    kvtop((caddr_t)sc->dmalist_pcmi));
1239 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL,
1240 	    AUICH_IOCE | AUICH_FEIE | AUICH_LVBIE | AUICH_RPBM);
1241 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_LVI,
1242 	    (sc->dmap_pcmi - 1 - sc->dmalist_pcmi) & AUICH_LVI_MASK);
1243 
1244 	return 0;
1245 }
1246 
1247 void
1248 auich_powerhook(why, self)
1249        int why;
1250        void *self;
1251 {
1252 	struct auich_softc *sc = (struct auich_softc *)self;
1253 
1254 	if (why != PWR_RESUME) {
1255 		/* Power down */
1256 		DPRINTF(1, ("auich: power down\n"));
1257 		sc->suspend = why;
1258 		auich_read_codec(sc, AC97_REG_EXT_AUDIO_CTRL, &sc->ext_ctrl);
1259 
1260 	} else {
1261 		/* Wake up */
1262 		DPRINTF(1, ("auich: power resume\n"));
1263 		if (sc->suspend == PWR_RESUME) {
1264 			printf("%s: resume without suspend?\n",
1265 			    sc->sc_dev.dv_xname);
1266 			sc->suspend = why;
1267 			return;
1268 		}
1269 		sc->suspend = why;
1270 		auich_reset_codec(sc);
1271 		DELAY(1000);
1272 		(sc->codec_if->vtbl->restore_ports)(sc->codec_if);
1273 		auich_write_codec(sc, AC97_REG_EXT_AUDIO_CTRL, sc->ext_ctrl);
1274 	}
1275 }
1276