xref: /openbsd-src/sys/dev/pci/auich.c (revision 8445c53715e7030056b779e8ab40efb7820981f2)
1 /*	$OpenBSD: auich.c,v 1.15 2001/09/10 17:38:54 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  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /* #define	AUICH_DEBUG */
32 /*
33  * AC'97 audio found on Intel 810/815/820/440MX chipsets.
34  *	http://developer.intel.com/design/chipsets/datashts/290655.htm
35  *	http://developer.intel.com/design/chipsets/manuals/298028.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_SRIE	0x20	/* int when 2ndary codec resume */
88 #define		AUICH_PRIE	0x10	/* int when primary codec resume */
89 #define		AUICH_ACLSO	0x08	/* aclink shut off */
90 #define		AUICH_WRESET	0x04	/* warm reset */
91 #define		AUICH_CRESET	0x02	/* cold reset */
92 #define		AUICH_GIE		0x01	/* gpi int enable */
93 #define	AUICH_GSTS	0x30
94 #define		AUICH_MD3		0x20000	/* pwr-dn semaphore for modem */
95 #define		AUICH_AD3		0x10000	/* pwr-dn semaphore for audio */
96 #define		AUICH_RCS		0x08000	/* read completion status */
97 #define		AUICH_B3S12	0x04000	/* bit 3 of slot 12 */
98 #define		AUICH_B2S12	0x02000	/* bit 2 of slot 12 */
99 #define		AUICH_B1S12	0x01000	/* bit 1 of slot 12 */
100 #define		AUICH_SRI		0x00800	/* secondary resume int */
101 #define		AUICH_PRI		0x00400	/* primary resume int */
102 #define		AUICH_SCR		0x00200	/* secondary codec ready */
103 #define		AUICH_PCR		0x00100	/* primary codec ready */
104 #define		AUICH_MINT	0x00080	/* mic in int */
105 #define		AUICH_POINT	0x00040	/* pcm out int */
106 #define		AUICH_PIINT	0x00020	/* pcm in int */
107 #define		AUICH_MOINT	0x00004	/* modem out int */
108 #define		AUICH_MIINT	0x00002	/* modem in int */
109 #define		AUICH_GSCI	0x00001	/* gpi status change */
110 #define		AUICH_GSTS_BITS	"\020\01gsci\02miict\03moint\06piint\07point\010mint\011pcr\012scr\013pri\014sri\015b1s12\016b2s12\017b3s12\020rcs\021ad3\022md3"
111 #define	AUICH_CAS		0x34	/* 1/8 bit */
112 #define	AUICH_SEMATIMO		1000	/* us */
113 
114 /*
115  * according to the dev/audiovar.h AU_RING_SIZE is 2^16, what fits
116  * in our limits perfectly, i.e. setting it to higher value
117  * in your kernel config would improve perfomance, still 2^21 is the max
118  */
119 #define	AUICH_DMALIST_MAX	32
120 #define	AUICH_DMASEG_MAX	(65536*2)	/* 64k samples, 2x16 bit samples */
121 struct auich_dmalist {
122 	u_int32_t	base;
123 	u_int32_t	len;
124 #define	AUICH_DMAF_IOC	0x80000000	/* 1-int on complete */
125 #define	AUICH_DMAF_BUP	0x40000000	/* 0-retrans last, 1-transmit 0 */
126 };
127 
128 struct auich_dma {
129 	bus_dmamap_t map;
130 	caddr_t addr;
131 	bus_dma_segment_t segs[AUICH_DMALIST_MAX];
132 	int nsegs;
133 	size_t size;
134 	struct auich_dma *next;
135 };
136 
137 struct auich_softc {
138 	struct device sc_dev;
139 	void *sc_ih;
140 
141 	audio_device_t sc_audev;
142 
143 	bus_space_tag_t iot;
144 	bus_space_handle_t mix_ioh;
145 	bus_space_handle_t aud_ioh;
146 	bus_dma_tag_t dmat;
147 
148 	struct ac97_codec_if *codec_if;
149 	struct ac97_host_if host_if;
150 
151 	/* dma scatter-gather buffer lists, aligned to 8 bytes */
152 	struct auich_dmalist *dmalist_pcmo, *dmap_pcmo,
153 	    dmasto_pcmo[AUICH_DMALIST_MAX+1];
154 	struct auich_dmalist *dmalist_pcmi, *dmap_pcmi,
155 	    dmasto_pcmi[AUICH_DMALIST_MAX+1];;
156 	struct auich_dmalist *dmalist_mici, *dmap_mici,
157 	    dmasto_mici[AUICH_DMALIST_MAX+1];;
158 	/* i/o buffer pointers */
159 	u_int32_t pcmo_start, pcmo_p, pcmo_end;
160 	int pcmo_blksize, pcmo_fifoe;
161 	u_int32_t pcmi_start, pcmi_p, pcmi_end;
162 	int pcmi_blksize, pcmi_fifoe;
163 	u_int32_t mici_start, mici_p, mici_end;
164 	int mici_blksize, mici_fifoe;
165 	struct auich_dma *sc_dmas;
166 
167 	void (*sc_pintr) __P((void *));
168 	void *sc_parg;
169 
170 	void (*sc_rintr) __P((void *));
171 	void *sc_rarg;
172 };
173 
174 #ifdef AUICH_DEBUG
175 #define	DPRINTF(l,x)	do { if (auich_debug & (l)) printf x; } while(0)
176 int auich_debug = 0xfffe;
177 #define	AUICH_DEBUG_CODECIO	0x0001
178 #define	AUICH_DEBUG_DMA		0x0002
179 #define	AUICH_DEBUG_PARAM	0x0004
180 #else
181 #define	DPRINTF(x,y)	/* nothing */
182 #endif
183 
184 struct cfdriver	auich_cd = {
185 	NULL, "auich", DV_DULL
186 };
187 
188 int  auich_match __P((struct device *, void *, void *));
189 void auich_attach __P((struct device *, struct device *, void *));
190 int  auich_intr __P((void *));
191 
192 struct cfattach auich_ca = {
193 	sizeof(struct auich_softc), auich_match, auich_attach
194 };
195 
196 static const struct auich_devtype {
197 	int	product;
198 	int	options;
199 	char	name[8];
200 } auich_devices[] = {
201 	{ PCI_PRODUCT_INTEL_82801AA_ACA, 0, "ICH" },
202 	{ PCI_PRODUCT_INTEL_82801AB_ACA, 0, "ICH0" },
203 	{ PCI_PRODUCT_INTEL_82801BA_ACA, 0, "ICH2" },
204 	{ PCI_PRODUCT_INTEL_82801CA_CAM, 0, "ICH3" },
205 	{ PCI_PRODUCT_INTEL_82440MX_ACA, 0, "440MX" },
206 };
207 
208 int auich_open __P((void *, int));
209 void auich_close __P((void *));
210 int auich_query_encoding __P((void *, struct audio_encoding *));
211 int auich_set_params __P((void *, int, int, struct audio_params *,
212     struct audio_params *));
213 int auich_round_blocksize __P((void *, int));
214 int auich_halt_output __P((void *));
215 int auich_halt_input __P((void *));
216 int auich_getdev __P((void *, struct audio_device *));
217 int auich_set_port __P((void *, mixer_ctrl_t *));
218 int auich_get_port __P((void *, mixer_ctrl_t *));
219 int auich_query_devinfo __P((void *, mixer_devinfo_t *));
220 void *auich_allocm __P((void *, u_long, int, int));
221 void auich_freem __P((void *, void *, int));
222 u_long auich_round_buffersize __P((void *, u_long));
223 int auich_mappage __P((void *, void *, int, int));
224 int auich_get_props __P((void *));
225 int auich_trigger_output __P((void *, void *, void *, int, void (*)(void *),
226     void *, struct audio_params *));
227 int auich_trigger_input __P((void *, void *, void *, int, void (*)(void *),
228     void *, struct audio_params *));
229 
230 struct audio_hw_if auich_hw_if = {
231 	auich_open,
232 	auich_close,
233 	NULL,			/* drain */
234 	auich_query_encoding,
235 	auich_set_params,
236 	auich_round_blocksize,
237 	NULL,			/* commit_setting */
238 	NULL,			/* init_output */
239 	NULL,			/* init_input */
240 	NULL,			/* start_output */
241 	NULL,			/* start_input */
242 	auich_halt_output,
243 	auich_halt_input,
244 	NULL,			/* speaker_ctl */
245 	auich_getdev,
246 	NULL,			/* getfd */
247 	auich_set_port,
248 	auich_get_port,
249 	auich_query_devinfo,
250 	auich_allocm,
251 	auich_freem,
252 	auich_round_buffersize,
253 	auich_mappage,
254 	auich_get_props,
255 	auich_trigger_output,
256 	auich_trigger_input
257 };
258 
259 int  auich_attach_codec __P((void *, struct ac97_codec_if *));
260 int  auich_read_codec __P((void *, u_int8_t, u_int16_t *));
261 int  auich_write_codec __P((void *, u_int8_t, u_int16_t));
262 void auich_reset_codec __P((void *));
263 
264 int
265 auich_match(parent, match, aux)
266 	struct device *parent;
267 	void *match;
268 	void *aux;
269 {
270 	struct pci_attach_args *pa = aux;
271 	int i;
272 
273 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
274 		return 0;
275 
276 	for (i = sizeof(auich_devices)/sizeof(auich_devices[0]); i--;)
277 		if (PCI_PRODUCT(pa->pa_id) == auich_devices[i].product)
278 			return 1;
279 
280 	return 0;
281 }
282 
283 void
284 auich_attach(parent, self, aux)
285 	struct device *parent, *self;
286 	void *aux;
287 {
288 	struct auich_softc *sc = (struct auich_softc *)self;
289 	struct pci_attach_args *pa = aux;
290 	pci_intr_handle_t ih;
291 	bus_size_t mix_size, aud_size;
292 	pcireg_t csr;
293 	const char *intrstr;
294 	int i;
295 
296 	if (pci_mapreg_map(pa, AUICH_NAMBAR, PCI_MAPREG_TYPE_IO, 0,
297 			   &sc->iot, &sc->mix_ioh, NULL, &mix_size, 0)) {
298 		printf(": can't map codec i/o space\n");
299 		return;
300 	}
301 	if (pci_mapreg_map(pa, AUICH_NABMBAR, PCI_MAPREG_TYPE_IO, 0,
302 			   &sc->iot, &sc->aud_ioh, NULL, &aud_size, 0)) {
303 		printf(": can't map device i/o space\n");
304 		bus_space_unmap(sc->iot, sc->mix_ioh, mix_size);
305 		return;
306 	}
307 	sc->dmat = pa->pa_dmat;
308 
309 	/* enable bus mastering (should not it be mi?) */
310 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
311 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
312 	    csr | PCI_COMMAND_MASTER_ENABLE);
313 
314 	if (pci_intr_map(pa, &ih)) {
315 		printf(": can't map interrupt\n");
316 		bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
317 		bus_space_unmap(sc->iot, sc->mix_ioh, mix_size);
318 		return;
319 	}
320 	intrstr = pci_intr_string(pa->pa_pc, ih);
321 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, auich_intr, sc,
322 				       sc->sc_dev.dv_xname);
323 	if (!sc->sc_ih) {
324 		printf(": can't establish interrupt");
325 		if (intrstr)
326 			printf(" at %s", intrstr);
327 		printf("\n");
328 		bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
329 		bus_space_unmap(sc->iot, sc->mix_ioh, mix_size);
330 		return;
331 	}
332 
333 	for (i = sizeof(auich_devices)/sizeof(auich_devices[0]); i--;)
334 		if (PCI_PRODUCT(pa->pa_id) == auich_devices[i].product)
335 			break;
336 
337 	sprintf(sc->sc_audev.name, "%s AC97", auich_devices[i].name);
338 	sprintf(sc->sc_audev.version, "0x%02x", PCI_REVISION(pa->pa_class));
339 	strcpy(sc->sc_audev.config, sc->sc_dev.dv_xname);
340 
341 	printf(": %s %s\n", intrstr, sc->sc_audev.name);
342 
343 	/* allocate dma lists */
344 #define	a(a)	(void*)(((u_long)(a) + sizeof(*(a)) - 1) & ~(sizeof(*(a))-1))
345 	sc->dmalist_pcmo = sc->dmap_pcmo = a(sc->dmasto_pcmo);
346 	sc->dmalist_pcmi = sc->dmap_pcmi = a(sc->dmasto_pcmi);
347 	sc->dmalist_mici = sc->dmap_mici = a(sc->dmasto_mici);
348 #undef a
349 	DPRINTF(AUICH_DEBUG_DMA, ("auich_attach: lists %p %p %p\n",
350 	    sc->dmalist_pcmo, sc->dmalist_pcmi, sc->dmalist_mici));
351 
352 	/* Reset codec and AC'97 */
353 	auich_reset_codec(sc);
354 
355 	sc->host_if.arg = sc;
356 	sc->host_if.attach = auich_attach_codec;
357 	sc->host_if.read = auich_read_codec;
358 	sc->host_if.write = auich_write_codec;
359 	sc->host_if.reset = auich_reset_codec;
360 
361 	if (ac97_attach(&sc->host_if) != 0) {
362 		pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
363 		bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
364 		bus_space_unmap(sc->iot, sc->mix_ioh, mix_size);
365 		return;
366 	}
367 
368 	audio_attach_mi(&auich_hw_if, sc, &sc->sc_dev);
369 }
370 
371 int
372 auich_read_codec(v, reg, val)
373 	void *v;
374 	u_int8_t reg;
375 	u_int16_t *val;
376 {
377 	struct auich_softc *sc = v;
378 	int i;
379 
380 	/* wait for an access semaphore */
381 	for (i = AUICH_SEMATIMO; i-- &&
382 	    bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_CAS) & 1; DELAY(1));
383 
384 	if (i > 0) {
385 		*val = bus_space_read_2(sc->iot, sc->mix_ioh, reg);
386 		DPRINTF(AUICH_DEBUG_CODECIO, ("%s: read_codec(%x, %x)\n",
387 		    sc->sc_dev.dv_xname, reg, *val));
388 
389 		return 0;
390 	} else {
391 		DPRINTF(AUICH_DEBUG_CODECIO,
392 		    ("%s: read_codec timeout\n", sc->sc_dev.dv_xname));
393 		return -1;
394 	}
395 }
396 
397 int
398 auich_write_codec(v, reg, val)
399 	void *v;
400 	u_int8_t reg;
401 	u_int16_t val;
402 {
403 	struct auich_softc *sc = v;
404 	int i;
405 
406 	/* wait for an access semaphore */
407 	for (i = AUICH_SEMATIMO; i-- &&
408 	    bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_CAS) & 1; DELAY(1));
409 
410 	if (i > 0) {
411 		DPRINTF(AUICH_DEBUG_CODECIO, ("%s: write_codec(%x, %x)\n",
412 		    sc->sc_dev.dv_xname, reg, val));
413 		bus_space_write_2(sc->iot, sc->mix_ioh, reg, val);
414 		return 0;
415 	} else {
416 		DPRINTF(AUICH_DEBUG_CODECIO,
417 		    ("%s: write_codec timeout\n", sc->sc_dev.dv_xname));
418 		return -1;
419 	}
420 }
421 
422 int
423 auich_attach_codec(v, cif)
424 	void *v;
425 	struct ac97_codec_if *cif;
426 {
427 	struct auich_softc *sc = v;
428 
429 	sc->codec_if = cif;
430 	return 0;
431 }
432 
433 void
434 auich_reset_codec(v)
435 	void *v;
436 {
437 	struct auich_softc *sc = v;
438 	bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_GCTRL, 0);
439 	DELAY(10);
440 	bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_GCTRL, AUICH_CRESET);
441 }
442 
443 int
444 auich_open(v, flags)
445 	void *v;
446 	int flags;
447 {
448 	return 0;
449 }
450 
451 void
452 auich_close(v)
453 	void *v;
454 {
455 }
456 
457 int
458 auich_query_encoding(v, aep)
459 	void *v;
460 	struct audio_encoding *aep;
461 {
462 	switch (aep->index) {
463 	case 0:
464 		strcpy(aep->name, AudioEulinear);
465 		aep->encoding = AUDIO_ENCODING_ULINEAR;
466 		aep->precision = 8;
467 		aep->flags = 0;
468 		return (0);
469 	case 1:
470 		strcpy(aep->name, AudioEmulaw);
471 		aep->encoding = AUDIO_ENCODING_ULAW;
472 		aep->precision = 8;
473 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
474 		return (0);
475 	case 2:
476 		strcpy(aep->name, AudioEalaw);
477 		aep->encoding = AUDIO_ENCODING_ALAW;
478 		aep->precision = 8;
479 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
480 		return (0);
481 	case 3:
482 		strcpy(aep->name, AudioEslinear);
483 		aep->encoding = AUDIO_ENCODING_SLINEAR;
484 		aep->precision = 8;
485 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
486 		return (0);
487 	case 4:
488 		strcpy(aep->name, AudioEslinear_le);
489 		aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
490 		aep->precision = 16;
491 		aep->flags = 0;
492 		return (0);
493 	case 5:
494 		strcpy(aep->name, AudioEulinear_le);
495 		aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
496 		aep->precision = 16;
497 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
498 		return (0);
499 	case 6:
500 		strcpy(aep->name, AudioEslinear_be);
501 		aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
502 		aep->precision = 16;
503 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
504 		return (0);
505 	case 7:
506 		strcpy(aep->name, AudioEulinear_be);
507 		aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
508 		aep->precision = 16;
509 		aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
510 		return (0);
511 	default:
512 		return (EINVAL);
513 	}
514 }
515 
516 int
517 auich_set_params(v, setmode, usemode, play, rec)
518 	void *v;
519 	int setmode, usemode;
520 	struct audio_params *play, *rec;
521 {
522 	struct auich_softc *sc = v;
523 	int error;
524 
525 	if (setmode & AUMODE_PLAY) {
526 		play->factor = 1;
527 		play->sw_code = NULL;
528 		switch(play->encoding) {
529 		case AUDIO_ENCODING_ULAW:
530 			play->factor = 2;
531 			play->sw_code = mulaw_to_slinear16;
532 			break;
533 		case AUDIO_ENCODING_SLINEAR_LE:
534 			if (play->precision == 8)
535 				play->sw_code = change_sign8;
536 			break;
537 		case AUDIO_ENCODING_ULINEAR_LE:
538 			if (play->precision == 16)
539 				play->sw_code = change_sign16;
540 			break;
541 		case AUDIO_ENCODING_ALAW:
542 			play->factor = 2;
543 			play->sw_code = alaw_to_slinear16;
544 			break;
545 		case AUDIO_ENCODING_SLINEAR_BE:
546 			if (play->precision == 16)
547 				play->sw_code = swap_bytes;
548 			else
549 				play->sw_code = change_sign8;
550 			break;
551 		case AUDIO_ENCODING_ULINEAR_BE:
552 			if (play->precision == 16)
553 				play->sw_code = change_sign16_swap_bytes;
554 			break;
555 		default:
556 			return (EINVAL);
557 		}
558 
559 		if ((error = ac97_set_rate(sc->codec_if, play, AUMODE_PLAY)))
560 			return (error);
561 	}
562 
563 	if (setmode & AUMODE_RECORD) {
564 		rec->factor = 1;
565 		rec->sw_code = 0;
566 		switch(rec->encoding) {
567 		case AUDIO_ENCODING_ULAW:
568 			rec->sw_code = ulinear8_to_mulaw;
569 			break;
570 		case AUDIO_ENCODING_SLINEAR_LE:
571 			if (rec->precision == 8)
572 				rec->sw_code = change_sign8;
573 			break;
574 		case AUDIO_ENCODING_ULINEAR_LE:
575 			if (rec->precision == 16)
576 				rec->sw_code = change_sign16;
577 			break;
578 		case AUDIO_ENCODING_ALAW:
579 			rec->sw_code = ulinear8_to_alaw;
580 			break;
581 		case AUDIO_ENCODING_SLINEAR_BE:
582 			if (rec->precision == 16)
583 				rec->sw_code = swap_bytes;
584 			else
585 				rec->sw_code = change_sign8;
586 			break;
587 		case AUDIO_ENCODING_ULINEAR_BE:
588 			if (rec->precision == 16)
589 				rec->sw_code = swap_bytes_change_sign16;
590 			break;
591 		default:
592 			return (EINVAL);
593 		}
594 
595 		if ((error = ac97_set_rate(sc->codec_if, rec, AUMODE_RECORD)))
596 			return (error);
597 	}
598 
599 	return (0);
600 }
601 
602 int
603 auich_round_blocksize(v, blk)
604 	void *v;
605 	int blk;
606 {
607 	return blk & ~0x3f;
608 }
609 
610 int
611 auich_halt_output(v)
612 	void *v;
613 {
614 	struct auich_softc *sc = v;
615 
616 	DPRINTF(AUICH_DEBUG_DMA, ("%s: halt_output\n", sc->sc_dev.dv_xname));
617 
618 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CTRL, AUICH_RR);
619 
620 	return 0;
621 }
622 
623 int
624 auich_halt_input(v)
625 	void *v;
626 {
627 	struct auich_softc *sc = v;
628 
629 	DPRINTF(AUICH_DEBUG_DMA,
630 	    ("%s: halt_input\n", sc->sc_dev.dv_xname));
631 
632 	/* XXX halt both unless known otherwise */
633 
634 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL, AUICH_RR);
635 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_MICI + AUICH_CTRL, AUICH_RR);
636 
637 	return 0;
638 }
639 
640 int
641 auich_getdev(v, adp)
642 	void *v;
643 	struct audio_device *adp;
644 {
645 	struct auich_softc *sc = v;
646 	*adp = sc->sc_audev;
647 	return 0;
648 }
649 
650 int
651 auich_set_port(v, cp)
652 	void *v;
653 	mixer_ctrl_t *cp;
654 {
655 	struct auich_softc *sc = v;
656 	return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
657 }
658 
659 int
660 auich_get_port(v, cp)
661 	void *v;
662 	mixer_ctrl_t *cp;
663 {
664 	struct auich_softc *sc = v;
665 	return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
666 }
667 
668 int
669 auich_query_devinfo(v, dp)
670 	void *v;
671 	mixer_devinfo_t *dp;
672 {
673 	struct auich_softc *sc = v;
674 	return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp);
675 }
676 
677 void *
678 auich_allocm(v, size, pool, flags)
679 	void *v;
680 	u_long size;
681 	int pool, flags;
682 {
683 	struct auich_softc *sc = v;
684 	struct auich_dma *p;
685 	int error;
686 
687 	if (size > AUICH_DMALIST_MAX * AUICH_DMASEG_MAX)
688 		return NULL;
689 
690 	p = malloc(sizeof(*p), pool, flags);
691 	if (!p)
692 		return NULL;
693 	bzero(p, sizeof(*p));
694 
695 	p->size = size;
696 	if ((error = bus_dmamem_alloc(sc->dmat, p->size, NBPG, 0, p->segs,
697 	    1, &p->nsegs, BUS_DMA_NOWAIT)) != 0) {
698 		printf("%s: unable to allocate dma, error = %d\n",
699 		    sc->sc_dev.dv_xname, error);
700 		free(p, pool);
701 		return NULL;
702 	}
703 
704 	if ((error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size,
705 	    &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
706 		printf("%s: unable to map dma, error = %d\n",
707 		    sc->sc_dev.dv_xname, error);
708 		bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
709 		free(p, pool);
710 		return NULL;
711 	}
712 
713 	if ((error = bus_dmamap_create(sc->dmat, p->size, 1,
714 	    p->size, 0, BUS_DMA_NOWAIT, &p->map)) != 0) {
715 		printf("%s: unable to create dma map, error = %d\n",
716 		    sc->sc_dev.dv_xname, error);
717 		bus_dmamem_unmap(sc->dmat, p->addr, size);
718 		bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
719 		free(p, pool);
720 		return NULL;
721 	}
722 
723 	if ((error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size,
724 	    NULL, BUS_DMA_NOWAIT)) != 0) {
725 		printf("%s: unable to load dma map, error = %d\n",
726 		    sc->sc_dev.dv_xname, error);
727 		bus_dmamap_destroy(sc->dmat, p->map);
728 		bus_dmamem_unmap(sc->dmat, p->addr, size);
729 		bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
730 		free(p, pool);
731 		return NULL;
732 	}
733 
734 	p->next = sc->sc_dmas;
735 	sc->sc_dmas = p;
736 
737 	return p->addr;
738 }
739 
740 void
741 auich_freem(v, ptr, pool)
742 	void *v;
743 	void *ptr;
744 	int pool;
745 {
746 	struct auich_softc *sc = v;
747 	struct auich_dma *p;
748 
749 	for (p = sc->sc_dmas; p->addr != ptr; p = p->next)
750 		if (p->next == NULL) {
751 			printf("auich_freem: trying to free not allocated memory");
752 			return;
753 		}
754 
755 	bus_dmamap_unload(sc->dmat, p->map);
756 	bus_dmamap_destroy(sc->dmat, p->map);
757 	bus_dmamem_unmap(sc->dmat, p->addr, p->size);
758 	bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
759 	free(p, pool);
760 }
761 
762 u_long
763 auich_round_buffersize(v, size)
764 	void *v;
765 	u_long size;
766 {
767 	if (size > AUICH_DMALIST_MAX * AUICH_DMASEG_MAX)
768 		size = AUICH_DMALIST_MAX * AUICH_DMASEG_MAX;
769 
770 	return size;
771 }
772 
773 int
774 auich_mappage(v, mem, off, prot)
775 	void *v;
776 	void *mem;
777 	int off;
778 	int prot;
779 {
780 	struct auich_softc *sc = v;
781 	struct auich_dma *p;
782 
783 	if (off < 0)
784 		return -1;
785 
786 	for (p = sc->sc_dmas; p && p->addr != mem; p = p->next);
787 	if (!p)
788 		return -1;
789 
790 	return bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs,
791 	    off, prot, BUS_DMA_WAITOK);
792 }
793 
794 int
795 auich_get_props(v)
796 	void *v;
797 {
798 	return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
799 }
800 
801 int
802 auich_intr(v)
803 	void *v;
804 {
805 	struct auich_softc *sc = v;
806 	int ret = 0, sts, gsts, i;
807 
808 	gsts = bus_space_read_2(sc->iot, sc->aud_ioh, AUICH_GSTS);
809 	DPRINTF(AUICH_DEBUG_DMA, ("auich_intr: gsts=%b\n", gsts, AUICH_GSTS_BITS));
810 
811 	if (gsts & AUICH_POINT) {
812 		sts = bus_space_read_2(sc->iot, sc->aud_ioh, AUICH_PCMO+AUICH_STS);
813 		DPRINTF(AUICH_DEBUG_DMA,
814 		    ("auich_intr: osts=%b\n", sts, AUICH_ISTS_BITS));
815 
816 		if (sts & AUICH_FIFOE) {
817 			printf("%s: fifo underrun # %u\n",
818 			    sc->sc_dev.dv_xname, ++sc->pcmo_fifoe);
819 		}
820 
821 		i = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CIV);
822 		if (sts & (AUICH_LVBCI | AUICH_CELV)) {
823 			struct auich_dmalist *q, *qe;
824 
825 			q = sc->dmap_pcmo;
826 			qe = &sc->dmalist_pcmo[i];
827 
828 			while (q != qe) {
829 
830 				q->base = sc->pcmo_p;
831 				q->len = (sc->pcmo_blksize / 2) | AUICH_DMAF_IOC;
832 				DPRINTF(AUICH_DEBUG_DMA,
833 				    ("auich_intr: %p, %p = %x @ %p\n",
834 				    qe, q, sc->pcmo_blksize / 2, sc->pcmo_p));
835 
836 				sc->pcmo_p += sc->pcmo_blksize;
837 				if (sc->pcmo_p >= sc->pcmo_end)
838 					sc->pcmo_p = sc->pcmo_start;
839 
840 				if (++q == &sc->dmalist_pcmo[AUICH_DMALIST_MAX])
841 					q = sc->dmalist_pcmo;
842 			}
843 
844 			sc->dmap_pcmo = q;
845 			bus_space_write_1(sc->iot, sc->aud_ioh,
846 			    AUICH_PCMO + AUICH_LVI,
847 			    (sc->dmap_pcmo - sc->dmalist_pcmo - 1) &
848 			    AUICH_LVI_MASK);
849 		}
850 
851 		if (sts & AUICH_BCIS && sc->sc_pintr)
852 			sc->sc_pintr(sc->sc_parg);
853 
854 		/* int ack */
855 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_STS,
856 		    sts & (AUICH_LVBCI | AUICH_CELV | AUICH_BCIS | AUICH_FIFOE));
857 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_POINT);
858 		ret++;
859 	}
860 
861 	if (gsts & AUICH_PIINT) {
862 		sts = bus_space_read_2(sc->iot, sc->aud_ioh, AUICH_PCMI+AUICH_STS);
863 		DPRINTF(AUICH_DEBUG_DMA,
864 		    ("auich_intr: ists=%b\n", sts, AUICH_ISTS_BITS));
865 
866 		if (sts & AUICH_FIFOE) {
867 			printf("%s: in fifo overrun # %u\n",
868 			    sc->sc_dev.dv_xname, ++sc->pcmi_fifoe);
869 		}
870 
871 		i = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CIV);
872 		if (sts & (AUICH_LVBCI | AUICH_CELV)) {
873 			struct auich_dmalist *q, *qe;
874 
875 			q = sc->dmap_pcmi;
876 			qe = &sc->dmalist_pcmi[i];
877 
878 			while (q != qe) {
879 
880 				q->base = sc->pcmi_p;
881 				q->len = (sc->pcmi_blksize / 2) | AUICH_DMAF_IOC;
882 				DPRINTF(AUICH_DEBUG_DMA,
883 				    ("auich_intr: %p, %p = %x @ %p\n",
884 				    qe, q, sc->pcmi_blksize / 2, sc->pcmi_p));
885 
886 				sc->pcmi_p += sc->pcmi_blksize;
887 				if (sc->pcmi_p >= sc->pcmi_end)
888 					sc->pcmi_p = sc->pcmi_start;
889 
890 				if (++q == &sc->dmalist_pcmi[AUICH_DMALIST_MAX])
891 					q = sc->dmalist_pcmi;
892 			}
893 
894 			sc->dmap_pcmi = q;
895 			bus_space_write_1(sc->iot, sc->aud_ioh,
896 			    AUICH_PCMI + AUICH_LVI,
897 			    (sc->dmap_pcmi - sc->dmalist_pcmi - 1) &
898 			    AUICH_LVI_MASK);
899 		}
900 
901 		if (sts & AUICH_BCIS && sc->sc_rintr)
902 			sc->sc_rintr(sc->sc_rarg);
903 
904 		/* int ack */
905 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_STS,
906 		    sts & (AUICH_LVBCI | AUICH_CELV | AUICH_BCIS | AUICH_FIFOE));
907 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_POINT);
908 		ret++;
909 	}
910 
911 	if (gsts & AUICH_MIINT) {
912 		sts = bus_space_read_2(sc->iot, sc->aud_ioh, AUICH_MICI+AUICH_STS);
913 		DPRINTF(AUICH_DEBUG_DMA,
914 		    ("auich_intr: ists=%b\n", sts, AUICH_ISTS_BITS));
915 		if (sts & AUICH_FIFOE)
916 			printf("%s: mic fifo overrun\n", sc->sc_dev.dv_xname);
917 
918 		/* TODO mic input dma */
919 
920 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_MIINT);
921 	}
922 
923 	return ret;
924 }
925 
926 int
927 auich_trigger_output(v, start, end, blksize, intr, arg, param)
928 	void *v;
929 	void *start, *end;
930 	int blksize;
931 	void (*intr)(void *);
932 	void *arg;
933 	struct audio_params *param;
934 {
935 	struct auich_softc *sc = v;
936 	struct auich_dmalist *q;
937 
938 	DPRINTF(AUICH_DEBUG_DMA,
939 	    ("auich_trigger_output(%x, %x, %d, %p, %p, %p)\n",
940 	    kvtop((caddr_t)start), kvtop((caddr_t)end),
941 	    blksize, intr, arg, param));
942 
943 #ifdef DIAGNOSTIC
944 	{
945 	struct auich_dma *p;
946 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
947 	if (!p)
948 		return -1;
949 	}
950 #endif
951 	sc->sc_pintr = intr;
952 	sc->sc_parg = arg;
953 
954 	/*
955 	 * The logic behind this is:
956 	 * setup one buffer to play, then LVI dump out the rest
957 	 * to the scatter-gather chain.
958 	 */
959 	sc->pcmo_start = kvtop((caddr_t)start);
960 	sc->pcmo_p = sc->pcmo_start + blksize;
961 	sc->pcmo_end = kvtop((caddr_t)end);
962 	sc->pcmo_blksize = blksize;
963 
964 	q = sc->dmap_pcmo = sc->dmalist_pcmo;
965 	q->base = sc->pcmo_start;
966 	q->len = (blksize / 2) | AUICH_DMAF_IOC;
967 	if (++q == &sc->dmalist_pcmo[AUICH_DMALIST_MAX])
968 		q = sc->dmalist_pcmo;
969 	sc->dmap_pcmo = q;
970 
971 	bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_BDBAR,
972 	    kvtop((caddr_t)sc->dmalist_pcmo));
973 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CTRL,
974 	    AUICH_IOCE | AUICH_FEIE | AUICH_LVBIE | AUICH_RPBM);
975 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_LVI,
976 	    (sc->dmap_pcmo - 1 - sc->dmalist_pcmo) & AUICH_LVI_MASK);
977 
978 	return 0;
979 }
980 
981 int
982 auich_trigger_input(v, start, end, blksize, intr, arg, param)
983 	void *v;
984 	void *start, *end;
985 	int blksize;
986 	void (*intr)(void *);
987 	void *arg;
988 	struct audio_params *param;
989 {
990 	struct auich_softc *sc = v;
991 	struct auich_dmalist *q;
992 
993 	DPRINTF(AUICH_DEBUG_DMA,
994 	    ("auich_trigger_input(%x, %x, %d, %p, %p, %p)\n",
995 	    kvtop((caddr_t)start), kvtop((caddr_t)end),
996 	    blksize, intr, arg, param));
997 
998 #ifdef DIAGNOSTIC
999 	{
1000 	struct auich_dma *p;
1001 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1002 	if (!p)
1003 		return -1;
1004 	}
1005 #endif
1006 	sc->sc_rintr = intr;
1007 	sc->sc_rarg = arg;
1008 
1009 	/*
1010 	 * The logic behind this is:
1011 	 * setup one buffer to play, then LVI dump out the rest
1012 	 * to the scatter-gather chain.
1013 	 */
1014 	sc->pcmi_start = kvtop((caddr_t)start);
1015 	sc->pcmi_p = sc->pcmi_start + blksize;
1016 	sc->pcmi_end = kvtop((caddr_t)end);
1017 	sc->pcmi_blksize = blksize;
1018 
1019 	q = sc->dmap_pcmi = sc->dmalist_pcmi;
1020 	q->base = sc->pcmi_start;
1021 	q->len = (blksize / 2) | AUICH_DMAF_IOC;
1022 	if (++q == &sc->dmalist_pcmi[AUICH_DMALIST_MAX])
1023 		q = sc->dmalist_pcmi;
1024 	sc->dmap_pcmi = q;
1025 
1026 	bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_BDBAR,
1027 	    kvtop((caddr_t)sc->dmalist_pcmi));
1028 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL,
1029 	    AUICH_IOCE | AUICH_FEIE | AUICH_LVBIE | AUICH_RPBM);
1030 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_LVI,
1031 	    (sc->dmap_pcmi - 1 - sc->dmalist_pcmi) & AUICH_LVI_MASK);
1032 
1033 	return 0;
1034 }
1035 
1036