xref: /openbsd-src/sys/dev/pci/auich.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: auich.c,v 1.12 2001/06/12 15:40:30 niklas 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_82440MX_ACA, 0, "440MX" },
205 };
206 
207 int auich_open __P((void *, int));
208 void auich_close __P((void *));
209 int auich_query_encoding __P((void *, struct audio_encoding *));
210 int auich_set_params __P((void *, int, int, struct audio_params *,
211     struct audio_params *));
212 int auich_round_blocksize __P((void *, int));
213 int auich_halt_output __P((void *));
214 int auich_halt_input __P((void *));
215 int auich_getdev __P((void *, struct audio_device *));
216 int auich_set_port __P((void *, mixer_ctrl_t *));
217 int auich_get_port __P((void *, mixer_ctrl_t *));
218 int auich_query_devinfo __P((void *, mixer_devinfo_t *));
219 void *auich_allocm __P((void *, u_long, int, int));
220 void auich_freem __P((void *, void *, int));
221 u_long auich_round_buffersize __P((void *, u_long));
222 int auich_mappage __P((void *, void *, int, int));
223 int auich_get_props __P((void *));
224 int auich_trigger_output __P((void *, void *, void *, int, void (*)(void *),
225     void *, struct audio_params *));
226 int auich_trigger_input __P((void *, void *, void *, int, void (*)(void *),
227     void *, struct audio_params *));
228 
229 struct audio_hw_if auich_hw_if = {
230 	auich_open,
231 	auich_close,
232 	NULL,			/* drain */
233 	auich_query_encoding,
234 	auich_set_params,
235 	auich_round_blocksize,
236 	NULL,			/* commit_setting */
237 	NULL,			/* init_output */
238 	NULL,			/* init_input */
239 	NULL,			/* start_output */
240 	NULL,			/* start_input */
241 	auich_halt_output,
242 	auich_halt_input,
243 	NULL,			/* speaker_ctl */
244 	auich_getdev,
245 	NULL,			/* getfd */
246 	auich_set_port,
247 	auich_get_port,
248 	auich_query_devinfo,
249 	auich_allocm,
250 	auich_freem,
251 	auich_round_buffersize,
252 	auich_mappage,
253 	auich_get_props,
254 	auich_trigger_output,
255 	auich_trigger_input
256 };
257 
258 int  auich_attach_codec __P((void *, struct ac97_codec_if *));
259 int  auich_read_codec __P((void *, u_int8_t, u_int16_t *));
260 int  auich_write_codec __P((void *, u_int8_t, u_int16_t));
261 void auich_reset_codec __P((void *));
262 
263 int
264 auich_match(parent, match, aux)
265 	struct device *parent;
266 	void *match;
267 	void *aux;
268 {
269 	struct pci_attach_args *pa = aux;
270 	int i;
271 
272 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
273 		return 0;
274 
275 	for (i = sizeof(auich_devices)/sizeof(auich_devices[0]); i--;)
276 		if (PCI_PRODUCT(pa->pa_id) == auich_devices[i].product)
277 			return 1;
278 
279 	return 0;
280 }
281 
282 void
283 auich_attach(parent, self, aux)
284 	struct device *parent, *self;
285 	void *aux;
286 {
287 	struct auich_softc *sc = (struct auich_softc *)self;
288 	struct pci_attach_args *pa = aux;
289 	pci_intr_handle_t ih;
290 	bus_size_t mix_size, aud_size;
291 	pcireg_t csr;
292 	const char *intrstr;
293 	int i;
294 
295 	if (pci_mapreg_map(pa, AUICH_NAMBAR, PCI_MAPREG_TYPE_IO, 0,
296 			   &sc->iot, &sc->mix_ioh, NULL, &mix_size, 0)) {
297 		printf(": can't map codec i/o space\n");
298 		return;
299 	}
300 	if (pci_mapreg_map(pa, AUICH_NABMBAR, PCI_MAPREG_TYPE_IO, 0,
301 			   &sc->iot, &sc->aud_ioh, NULL, &aud_size, 0)) {
302 		printf(": can't map device i/o space\n");
303 		bus_space_unmap(sc->iot, sc->mix_ioh, mix_size);
304 		return;
305 	}
306 	sc->dmat = pa->pa_dmat;
307 
308 	/* enable bus mastering (should not it be mi?) */
309 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
310 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
311 	    csr | PCI_COMMAND_MASTER_ENABLE);
312 
313 	if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
314 			 pa->pa_intrline, &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 
694 	bzero(p, sizeof(p));
695 
696 	p->size = size;
697 	if ((error = bus_dmamem_alloc(sc->dmat, p->size, NBPG, 0, p->segs,
698 	    1, &p->nsegs, BUS_DMA_NOWAIT)) != 0) {
699 		printf("%s: unable to allocate dma, error = %d\n",
700 		    sc->sc_dev.dv_xname, error);
701 		free(p, pool);
702 		return NULL;
703 	}
704 
705 	if ((error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size,
706 	    &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
707 		printf("%s: unable to map dma, error = %d\n",
708 		    sc->sc_dev.dv_xname, error);
709 		bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
710 		free(p, pool);
711 		return NULL;
712 	}
713 
714 	if ((error = bus_dmamap_create(sc->dmat, p->size, 1,
715 	    p->size, 0, BUS_DMA_NOWAIT, &p->map)) != 0) {
716 		printf("%s: unable to create dma map, error = %d\n",
717 		    sc->sc_dev.dv_xname, error);
718 		bus_dmamem_unmap(sc->dmat, p->addr, size);
719 		bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
720 		free(p, pool);
721 		return NULL;
722 	}
723 
724 	if ((error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size,
725 	    NULL, BUS_DMA_NOWAIT)) != 0) {
726 		printf("%s: unable to load dma map, error = %d\n",
727 		    sc->sc_dev.dv_xname, error);
728 		bus_dmamap_destroy(sc->dmat, p->map);
729 		bus_dmamem_unmap(sc->dmat, p->addr, size);
730 		bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
731 		free(p, pool);
732 		return NULL;
733 	}
734 
735 	p->next = sc->sc_dmas;
736 	sc->sc_dmas = p;
737 
738 	return p->addr;
739 }
740 
741 void
742 auich_freem(v, ptr, pool)
743 	void *v;
744 	void *ptr;
745 	int pool;
746 {
747 	struct auich_softc *sc = v;
748 	struct auich_dma *p;
749 
750 	for (p = sc->sc_dmas; p->addr != ptr; p = p->next)
751 		if (p->next == NULL) {
752 			printf("auich_freem: trying to free not allocated memory");
753 			return;
754 		}
755 
756 	bus_dmamap_unload(sc->dmat, p->map);
757 	bus_dmamap_destroy(sc->dmat, p->map);
758 	bus_dmamem_unmap(sc->dmat, p->addr, p->size);
759 	bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
760 	free(p, pool);
761 }
762 
763 u_long
764 auich_round_buffersize(v, size)
765 	void *v;
766 	u_long size;
767 {
768 	if (size > AUICH_DMALIST_MAX * AUICH_DMASEG_MAX)
769 		size = AUICH_DMALIST_MAX * AUICH_DMASEG_MAX;
770 
771 	return size;
772 }
773 
774 int
775 auich_mappage(v, mem, off, prot)
776 	void *v;
777 	void *mem;
778 	int off;
779 	int prot;
780 {
781 	struct auich_softc *sc = v;
782 	struct auich_dma *p;
783 
784 	if (off < 0)
785 		return -1;
786 
787 	for (p = sc->sc_dmas; p && p->addr != mem; p = p->next);
788 	if (!p)
789 		return -1;
790 
791 	return bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs,
792 	    off, prot, BUS_DMA_WAITOK);
793 }
794 
795 int
796 auich_get_props(v)
797 	void *v;
798 {
799 	return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
800 }
801 
802 int
803 auich_intr(v)
804 	void *v;
805 {
806 	struct auich_softc *sc = v;
807 	int ret = 0, sts, gsts, i;
808 
809 	gsts = bus_space_read_2(sc->iot, sc->aud_ioh, AUICH_GSTS);
810 	DPRINTF(AUICH_DEBUG_DMA, ("auich_intr: gsts=%b\n", gsts, AUICH_GSTS_BITS));
811 
812 	if (gsts & AUICH_POINT) {
813 		sts = bus_space_read_2(sc->iot, sc->aud_ioh, AUICH_PCMO+AUICH_STS);
814 		DPRINTF(AUICH_DEBUG_DMA,
815 		    ("auich_intr: osts=%b\n", sts, AUICH_ISTS_BITS));
816 
817 		if (sts & AUICH_FIFOE) {
818 			printf("%s: fifo underrun # %u\n",
819 			    sc->sc_dev.dv_xname, ++sc->pcmo_fifoe);
820 		}
821 
822 		i = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CIV);
823 		if (sts & (AUICH_LVBCI | AUICH_CELV)) {
824 			struct auich_dmalist *q, *qe;
825 
826 			q = sc->dmap_pcmo;
827 			qe = &sc->dmalist_pcmo[i];
828 
829 			while (q != qe) {
830 
831 				q->base = sc->pcmo_p;
832 				q->len = (sc->pcmo_blksize / 2) | AUICH_DMAF_IOC;
833 				DPRINTF(AUICH_DEBUG_DMA,
834 				    ("auich_intr: %p, %p = %x @ %p\n",
835 				    qe, q, sc->pcmo_blksize / 2, sc->pcmo_p));
836 
837 				sc->pcmo_p += sc->pcmo_blksize;
838 				if (sc->pcmo_p >= sc->pcmo_end)
839 					sc->pcmo_p = sc->pcmo_start;
840 
841 				if (++q == &sc->dmalist_pcmo[AUICH_DMALIST_MAX])
842 					q = sc->dmalist_pcmo;
843 			}
844 
845 			sc->dmap_pcmo = q;
846 			bus_space_write_1(sc->iot, sc->aud_ioh,
847 			    AUICH_PCMO + AUICH_LVI,
848 			    (sc->dmap_pcmo - sc->dmalist_pcmo - 1) &
849 			    AUICH_LVI_MASK);
850 		}
851 
852 		if (sts & AUICH_BCIS && sc->sc_pintr)
853 			sc->sc_pintr(sc->sc_parg);
854 
855 		/* int ack */
856 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_STS,
857 		    sts & (AUICH_LVBCI | AUICH_CELV | AUICH_BCIS | AUICH_FIFOE));
858 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_POINT);
859 		ret++;
860 	}
861 
862 	if (gsts & AUICH_PIINT) {
863 		sts = bus_space_read_2(sc->iot, sc->aud_ioh, AUICH_PCMI+AUICH_STS);
864 		DPRINTF(AUICH_DEBUG_DMA,
865 		    ("auich_intr: ists=%b\n", sts, AUICH_ISTS_BITS));
866 
867 		if (sts & AUICH_FIFOE) {
868 			printf("%s: in fifo overrun # %u\n",
869 			    sc->sc_dev.dv_xname, ++sc->pcmi_fifoe);
870 		}
871 
872 		i = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CIV);
873 		if (sts & (AUICH_LVBCI | AUICH_CELV)) {
874 			struct auich_dmalist *q, *qe;
875 
876 			q = sc->dmap_pcmi;
877 			qe = &sc->dmalist_pcmi[i];
878 
879 			while (q != qe) {
880 
881 				q->base = sc->pcmi_p;
882 				q->len = (sc->pcmi_blksize / 2) | AUICH_DMAF_IOC;
883 				DPRINTF(AUICH_DEBUG_DMA,
884 				    ("auich_intr: %p, %p = %x @ %p\n",
885 				    qe, q, sc->pcmi_blksize / 2, sc->pcmi_p));
886 
887 				sc->pcmi_p += sc->pcmi_blksize;
888 				if (sc->pcmi_p >= sc->pcmi_end)
889 					sc->pcmi_p = sc->pcmi_start;
890 
891 				if (++q == &sc->dmalist_pcmi[AUICH_DMALIST_MAX])
892 					q = sc->dmalist_pcmi;
893 			}
894 
895 			sc->dmap_pcmi = q;
896 			bus_space_write_1(sc->iot, sc->aud_ioh,
897 			    AUICH_PCMI + AUICH_LVI,
898 			    (sc->dmap_pcmi - sc->dmalist_pcmi - 1) &
899 			    AUICH_LVI_MASK);
900 		}
901 
902 		if (sts & AUICH_BCIS && sc->sc_rintr)
903 			sc->sc_rintr(sc->sc_rarg);
904 
905 		/* int ack */
906 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_STS,
907 		    sts & (AUICH_LVBCI | AUICH_CELV | AUICH_BCIS | AUICH_FIFOE));
908 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_POINT);
909 		ret++;
910 	}
911 
912 	if (gsts & AUICH_MIINT) {
913 		sts = bus_space_read_2(sc->iot, sc->aud_ioh, AUICH_MICI+AUICH_STS);
914 		DPRINTF(AUICH_DEBUG_DMA,
915 		    ("auich_intr: ists=%b\n", sts, AUICH_ISTS_BITS));
916 		if (sts & AUICH_FIFOE)
917 			printf("%s: mic fifo overrun\n", sc->sc_dev.dv_xname);
918 
919 		/* TODO mic input dma */
920 
921 		bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_MIINT);
922 	}
923 
924 	return ret;
925 }
926 
927 int
928 auich_trigger_output(v, start, end, blksize, intr, arg, param)
929 	void *v;
930 	void *start, *end;
931 	int blksize;
932 	void (*intr)(void *);
933 	void *arg;
934 	struct audio_params *param;
935 {
936 	struct auich_softc *sc = v;
937 	struct auich_dmalist *q;
938 
939 	DPRINTF(AUICH_DEBUG_DMA,
940 	    ("auich_trigger_output(%x, %x, %d, %p, %p, %p)\n",
941 	    kvtop((caddr_t)start), kvtop((caddr_t)end),
942 	    blksize, intr, arg, param));
943 
944 #ifdef DIAGNOSTIC
945 	{
946 	struct auich_dma *p;
947 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
948 	if (!p)
949 		return -1;
950 	}
951 #endif
952 	sc->sc_pintr = intr;
953 	sc->sc_parg = arg;
954 
955 	/*
956 	 * The logic behind this is:
957 	 * setup one buffer to play, then LVI dump out the rest
958 	 * to the scatter-gather chain.
959 	 */
960 	sc->pcmo_start = kvtop((caddr_t)start);
961 	sc->pcmo_p = sc->pcmo_start + blksize;
962 	sc->pcmo_end = kvtop((caddr_t)end);
963 	sc->pcmo_blksize = blksize;
964 
965 	q = sc->dmap_pcmo = sc->dmalist_pcmo;
966 	q->base = sc->pcmo_start;
967 	q->len = (blksize / 2) | AUICH_DMAF_IOC;
968 	if (++q == &sc->dmalist_pcmo[AUICH_DMALIST_MAX])
969 		q = sc->dmalist_pcmo;
970 	sc->dmap_pcmo = q;
971 
972 	bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_BDBAR,
973 	    kvtop((caddr_t)sc->dmalist_pcmo));
974 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CTRL,
975 	    AUICH_IOCE | AUICH_FEIE | AUICH_LVBIE | AUICH_RPBM);
976 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_LVI,
977 	    (sc->dmap_pcmo - 1 - sc->dmalist_pcmo) & AUICH_LVI_MASK);
978 
979 	return 0;
980 }
981 
982 int
983 auich_trigger_input(v, start, end, blksize, intr, arg, param)
984 	void *v;
985 	void *start, *end;
986 	int blksize;
987 	void (*intr)(void *);
988 	void *arg;
989 	struct audio_params *param;
990 {
991 	struct auich_softc *sc = v;
992 	struct auich_dmalist *q;
993 
994 	DPRINTF(AUICH_DEBUG_DMA,
995 	    ("auich_trigger_input(%x, %x, %d, %p, %p, %p)\n",
996 	    kvtop((caddr_t)start), kvtop((caddr_t)end),
997 	    blksize, intr, arg, param));
998 
999 #ifdef DIAGNOSTIC
1000 	{
1001 	struct auich_dma *p;
1002 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1003 	if (!p)
1004 		return -1;
1005 	}
1006 #endif
1007 	sc->sc_rintr = intr;
1008 	sc->sc_rarg = arg;
1009 
1010 	/*
1011 	 * The logic behind this is:
1012 	 * setup one buffer to play, then LVI dump out the rest
1013 	 * to the scatter-gather chain.
1014 	 */
1015 	sc->pcmi_start = kvtop((caddr_t)start);
1016 	sc->pcmi_p = sc->pcmi_start + blksize;
1017 	sc->pcmi_end = kvtop((caddr_t)end);
1018 	sc->pcmi_blksize = blksize;
1019 
1020 	q = sc->dmap_pcmi = sc->dmalist_pcmi;
1021 	q->base = sc->pcmi_start;
1022 	q->len = (blksize / 2) | AUICH_DMAF_IOC;
1023 	if (++q == &sc->dmalist_pcmi[AUICH_DMALIST_MAX])
1024 		q = sc->dmalist_pcmi;
1025 	sc->dmap_pcmi = q;
1026 
1027 	bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_BDBAR,
1028 	    kvtop((caddr_t)sc->dmalist_pcmi));
1029 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL,
1030 	    AUICH_IOCE | AUICH_FEIE | AUICH_LVBIE | AUICH_RPBM);
1031 	bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_LVI,
1032 	    (sc->dmap_pcmi - 1 - sc->dmalist_pcmi) & AUICH_LVI_MASK);
1033 
1034 	return 0;
1035 }
1036 
1037