xref: /openbsd-src/sys/arch/macppc/dev/awacs.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: awacs.c,v 1.27 2011/09/04 18:48:10 miod Exp $	*/
2 /*	$NetBSD: awacs.c,v 1.4 2001/02/26 21:07:51 wiz Exp $	*/
3 
4 /*-
5  * Copyright (c) 2000 Tsubai Masanari.  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 BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/param.h>
31 #include <sys/audioio.h>
32 #include <sys/device.h>
33 #include <sys/malloc.h>
34 #include <sys/systm.h>
35 
36 #include <dev/auconv.h>
37 #include <dev/audio_if.h>
38 #include <dev/mulaw.h>
39 
40 #include <machine/bus.h>
41 #include <machine/autoconf.h>
42 #include <macppc/dev/dbdma.h>
43 
44 #ifdef AWACS_DEBUG
45 # define DPRINTF printf
46 #else
47 # define DPRINTF while (0) printf
48 #endif
49 
50 #define	AWACS_DMALIST_MAX	32
51 #define	AWACS_DMASEG_MAX	NBPG
52 
53 struct awacs_dma {
54 	bus_dmamap_t map;
55 	caddr_t addr;
56 	bus_dma_segment_t segs[AWACS_DMALIST_MAX];
57 	int nsegs;
58 	size_t size;
59 	struct awacs_dma *next;
60 };
61 
62 
63 struct awacs_softc {
64 	struct device sc_dev;
65 
66 	void (*sc_ointr)(void *);	/* dma completion intr handler */
67 	void *sc_oarg;			/* arg for sc_ointr() */
68 
69 	void (*sc_iintr)(void *);	/* dma completion intr handler */
70 	void *sc_iarg;			/* arg for sc_iintr() */
71 
72 	u_int sc_record_source;		/* recording source mask */
73 	u_int sc_output_mask;		/* output source mask */
74 
75 	char *sc_reg;
76 	u_int sc_codecctl0;
77 	u_int sc_codecctl1;
78 	u_int sc_codecctl2;
79 	u_int sc_codecctl4;
80 	u_int sc_soundctl;
81 
82 	bus_dma_tag_t sc_dmat;
83 	struct dbdma_regmap *sc_odma;
84 	struct dbdma_regmap *sc_idma;
85 	struct dbdma_command *sc_odmacmd, *sc_odmap;
86 	struct dbdma_command *sc_idmacmd, *sc_idmap;
87 	dbdma_t sc_odbdma, sc_idbdma;
88 
89 	struct awacs_dma *sc_dmas;
90 };
91 
92 int awacs_match(struct device *, void *, void *);
93 void awacs_attach(struct device *, struct device *, void *);
94 int awacs_intr(void *);
95 int awacs_tx_intr(void *);
96 int awacs_rx_intr(void *);
97 
98 int awacs_open(void *, int);
99 void awacs_close(void *);
100 int awacs_query_encoding(void *, struct audio_encoding *);
101 int awacs_set_params(void *, int, int, struct audio_params *,
102 			 struct audio_params *);
103 int awacs_round_blocksize(void *, int);
104 int awacs_trigger_output(void *, void *, void *, int, void (*)(void *),
105 			     void *, struct audio_params *);
106 int awacs_trigger_input(void *, void *, void *, int, void (*)(void *),
107 			    void *, struct audio_params *);
108 int awacs_halt_output(void *);
109 int awacs_halt_input(void *);
110 int awacs_getdev(void *, struct audio_device *);
111 int awacs_set_port(void *, mixer_ctrl_t *);
112 int awacs_get_port(void *, mixer_ctrl_t *);
113 int awacs_query_devinfo(void *, mixer_devinfo_t *);
114 size_t awacs_round_buffersize(void *, int, size_t);
115 paddr_t awacs_mappage(void *, void *, off_t, int);
116 int awacs_get_props(void *);
117 void *awacs_allocm(void *, int, size_t, int, int);
118 
119 static inline u_int awacs_read_reg(struct awacs_softc *, int);
120 static inline void awacs_write_reg(struct awacs_softc *, int, int);
121 void awacs_write_codec(struct awacs_softc *, int);
122 void awacs_set_speaker_volume(struct awacs_softc *, int, int);
123 void awacs_set_ext_volume(struct awacs_softc *, int, int);
124 void awacs_set_rate(struct awacs_softc *, struct audio_params *);
125 
126 struct cfattach awacs_ca = {
127 	sizeof(struct awacs_softc), awacs_match, awacs_attach
128 };
129 
130 struct cfdriver awacs_cd = {
131 	NULL, "awacs", DV_DULL
132 };
133 
134 struct audio_hw_if awacs_hw_if = {
135 	awacs_open,
136 	awacs_close,
137 	NULL,			/* drain */
138 	awacs_query_encoding,
139 	awacs_set_params,
140 	awacs_round_blocksize,
141 	NULL,			/* commit_setting */
142 	NULL,			/* init_output */
143 	NULL,			/* init_input */
144 	NULL,			/* start_output */
145 	NULL,			/* start_input */
146 	awacs_halt_output,
147 	awacs_halt_input,
148 	NULL,			/* speaker_ctl */
149 	awacs_getdev,
150 	NULL,			/* getfd */
151 	awacs_set_port,
152 	awacs_get_port,
153 	awacs_query_devinfo,
154 	awacs_allocm,		/* allocm */
155 	NULL,			/* freem */
156 	awacs_round_buffersize,	/* round_buffersize */
157 	awacs_mappage,
158 	awacs_get_props,
159 	awacs_trigger_output,
160 	awacs_trigger_input,
161 	NULL
162 };
163 
164 struct audio_device awacs_device = {
165 	"AWACS",
166 	"",
167 	"awacs"
168 };
169 
170 /* register offset */
171 #define AWACS_SOUND_CTRL	0x00
172 #define AWACS_CODEC_CTRL	0x10
173 #define AWACS_CODEC_STATUS	0x20
174 #define AWACS_CLIP_COUNT	0x30
175 #define AWACS_BYTE_SWAP		0x40
176 
177 /* sound control */
178 #define AWACS_INPUT_SUBFRAME0	0x00000001
179 #define AWACS_INPUT_SUBFRAME1	0x00000002
180 #define AWACS_INPUT_SUBFRAME2	0x00000004
181 #define AWACS_INPUT_SUBFRAME3	0x00000008
182 
183 #define AWACS_OUTPUT_SUBFRAME0	0x00000010
184 #define AWACS_OUTPUT_SUBFRAME1	0x00000020
185 #define AWACS_OUTPUT_SUBFRAME2	0x00000040
186 #define AWACS_OUTPUT_SUBFRAME3	0x00000080
187 
188 #define AWACS_RATE_44100	0x00000000
189 #define AWACS_RATE_29400	0x00000100
190 #define AWACS_RATE_22050	0x00000200
191 #define AWACS_RATE_17640	0x00000300
192 #define AWACS_RATE_14700	0x00000400
193 #define AWACS_RATE_11025	0x00000500
194 #define AWACS_RATE_8820		0x00000600
195 #define AWACS_RATE_7350		0x00000700
196 #define AWACS_RATE_MASK		0x00000700
197 
198 #define AWACS_CTL_CNTRLERR 	(1 << 11)
199 #define AWACS_CTL_PORTCHG 	(1 << 12)
200 #define AWACS_INT_CNTRLERR 	(1 << 13)
201 #define AWACS_INT_PORTCHG 	(1 << 14)
202 
203 /* codec control */
204 #define AWACS_CODEC_ADDR0	0x00000000
205 #define AWACS_CODEC_ADDR1	0x00001000
206 #define AWACS_CODEC_ADDR2	0x00002000
207 #define AWACS_CODEC_ADDR4	0x00004000
208 #define AWACS_CODEC_EMSEL0	0x00000000
209 #define AWACS_CODEC_EMSEL1	0x00400000
210 #define AWACS_CODEC_EMSEL2	0x00800000
211 #define AWACS_CODEC_EMSEL4	0x00c00000
212 #define AWACS_CODEC_BUSY	0x01000000
213 
214 /* cc0 */
215 #define AWACS_DEFAULT_CD_GAIN	0x000000bb
216 #define AWACS_INPUT_CD		0x00000200
217 #define AWACS_INPUT_LINE	0x00000400
218 #define AWACS_INPUT_MICROPHONE	0x00000800
219 #define AWACS_INPUT_MASK	0x00000e00
220 
221 /* cc1 */
222 #define AWACS_MUTE_SPEAKER	0x00000080
223 #define AWACS_MUTE_HEADPHONE	0x00000200
224 
225 const struct awacs_speed_tab {
226 	int rate;
227 	u_int32_t bits;
228 } awacs_speeds[] = {
229 	{  7350, AWACS_RATE_7350 },
230 	{  8820, AWACS_RATE_8820 },
231 	{ 11025, AWACS_RATE_11025 },
232 	{ 14700, AWACS_RATE_14700 },
233 	{ 17640, AWACS_RATE_17640 },
234 	{ 22050, AWACS_RATE_22050 },
235 	{ 29400, AWACS_RATE_29400 },
236 	{ 44100, AWACS_RATE_44100 },
237 };
238 
239 int
240 awacs_match(struct device *parent, void *match, void *aux)
241 {
242 	struct confargs *ca = aux;
243 
244 	if (strcmp(ca->ca_name, "awacs") != 0 &&
245 	    strcmp(ca->ca_name, "davbus") != 0)
246 		return 0;
247 
248 #ifdef DEBUG
249 	printf("awacs: matched %s nreg %d nintr %d\n",
250 		ca->ca_name, ca->ca_nreg, ca->ca_nintr);
251 #endif
252 
253 	if (ca->ca_nreg < 24 || ca->ca_nintr < 12)
254 		return 0;
255 
256 	/* XXX for now
257 	if (ca->ca_nintr > 12)
258 		return 0;
259 	*/
260 
261 	return 1;
262 }
263 
264 void
265 awacs_attach(struct device *parent, struct device *self, void *aux)
266 {
267 	struct awacs_softc *sc = (struct awacs_softc *)self;
268 	struct confargs *ca = aux;
269 	int cirq, oirq, iirq;
270 	int cirq_type, oirq_type, iirq_type;
271 
272 	ca->ca_reg[0] += ca->ca_baseaddr;
273 	ca->ca_reg[2] += ca->ca_baseaddr;
274 	ca->ca_reg[4] += ca->ca_baseaddr;
275 
276 	sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1]);
277 
278 	sc->sc_dmat = ca->ca_dmat;
279 	sc->sc_odma = mapiodev(ca->ca_reg[2], ca->ca_reg[3]); /* out */
280 	sc->sc_idma = mapiodev(ca->ca_reg[4], ca->ca_reg[5]); /* in */
281 	sc->sc_odbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX);
282 	sc->sc_odmacmd = sc->sc_odbdma->d_addr;
283 	sc->sc_idbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX);
284 	sc->sc_idmacmd = sc->sc_idbdma->d_addr;
285 
286 	if (ca->ca_nintr == 24) {
287 		cirq = ca->ca_intr[0];
288 		oirq = ca->ca_intr[2];
289 		iirq = ca->ca_intr[4];
290 		cirq_type = ca->ca_intr[1] ? IST_LEVEL : IST_EDGE;
291 		oirq_type = ca->ca_intr[3] ? IST_LEVEL : IST_EDGE;
292 		iirq_type = ca->ca_intr[5] ? IST_LEVEL : IST_EDGE;
293 	} else {
294 		cirq = ca->ca_intr[0];
295 		oirq = ca->ca_intr[1];
296 		iirq = ca->ca_intr[2];
297 		cirq_type = oirq_type = iirq_type = IST_LEVEL;
298 	}
299 	mac_intr_establish(parent, cirq, cirq_type, IPL_AUDIO, awacs_intr,
300 	    sc, sc->sc_dev.dv_xname);
301 	mac_intr_establish(parent, oirq, oirq_type, IPL_AUDIO, awacs_tx_intr,
302 	    sc, sc->sc_dev.dv_xname);
303 	mac_intr_establish(parent, iirq, iirq_type, IPL_AUDIO, awacs_rx_intr,
304 	    sc, sc->sc_dev.dv_xname);
305 
306 	printf(": irq %d,%d,%d",
307 		cirq, oirq, iirq);
308 
309 	sc->sc_soundctl = AWACS_INPUT_SUBFRAME0 | AWACS_OUTPUT_SUBFRAME0 |
310 	    AWACS_RATE_44100 | AWACS_INT_PORTCHG;
311 	awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
312 
313 	sc->sc_codecctl0 = AWACS_CODEC_ADDR0 | AWACS_CODEC_EMSEL0;
314 	sc->sc_codecctl1 = AWACS_CODEC_ADDR1 | AWACS_CODEC_EMSEL0;
315 	sc->sc_codecctl2 = AWACS_CODEC_ADDR2 | AWACS_CODEC_EMSEL0;
316 	sc->sc_codecctl4 = AWACS_CODEC_ADDR4 | AWACS_CODEC_EMSEL0;
317 
318 	sc->sc_codecctl0 |= AWACS_INPUT_CD | AWACS_DEFAULT_CD_GAIN;
319 	awacs_write_codec(sc, sc->sc_codecctl0);
320 
321 	/* Set initial volume[s] */
322 	awacs_set_speaker_volume(sc, 80, 80);
323 	awacs_set_ext_volume(sc, 80, 80);
324 
325 	/* Set loopback (for CD?) */
326 	/* sc->sc_codecctl1 |= 0x440; */
327 	sc->sc_codecctl1 |= 0x40;
328 	awacs_write_codec(sc, sc->sc_codecctl1);
329 
330 	/* check for headphone present */
331 	if (awacs_read_reg(sc, AWACS_CODEC_STATUS) & 0x8) {
332 		/* default output to speakers */
333 		printf(" headphones");
334 		sc->sc_output_mask = 1 << 1;
335 		sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE;
336 		sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER;
337 		awacs_write_codec(sc, sc->sc_codecctl1);
338 	} else {
339 		/* default output to speakers */
340 		printf(" speaker");
341 		sc->sc_output_mask = 1 << 0;
342 		sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
343 		sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE;
344 		awacs_write_codec(sc, sc->sc_codecctl1);
345 	}
346 
347 	/* default input from CD */
348 	sc->sc_record_source = 1 << 0;
349 	sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
350 	sc->sc_codecctl0 |= AWACS_INPUT_CD;
351 	awacs_write_codec(sc, sc->sc_codecctl0);
352 
353 	/* Enable interrupts and looping mode. */
354 	/* XXX ... */
355 	awacs_halt_output(sc);
356 	awacs_halt_input(sc);
357 	printf("\n");
358 
359 	audio_attach_mi(&awacs_hw_if, sc, &sc->sc_dev);
360 }
361 
362 u_int
363 awacs_read_reg(struct awacs_softc *sc, int reg)
364 {
365 	char *addr = sc->sc_reg;
366 
367 	return in32rb(addr + reg);
368 }
369 
370 void
371 awacs_write_reg(struct awacs_softc *sc, int reg, int val)
372 {
373 	char *addr = sc->sc_reg;
374 
375 	out32rb(addr + reg, val);
376 }
377 
378 void
379 awacs_write_codec(struct awacs_softc *sc, int value)
380 {
381 	awacs_write_reg(sc, AWACS_CODEC_CTRL, value);
382 	while (awacs_read_reg(sc, AWACS_CODEC_CTRL) & AWACS_CODEC_BUSY);
383 }
384 
385 int
386 awacs_intr(void *v)
387 {
388 	int reason;
389 	struct awacs_softc *sc = v;
390 	reason = awacs_read_reg(sc, AWACS_SOUND_CTRL);
391 
392 	if (reason & AWACS_CTL_CNTRLERR) {
393 		/* change outputs ?? */
394 	}
395 	if (reason & AWACS_CTL_PORTCHG) {
396 #ifdef DEBUG
397 		printf("status = %x\n", awacs_read_reg(sc, AWACS_CODEC_STATUS));
398 #endif
399 
400 		if (awacs_read_reg(sc, AWACS_CODEC_STATUS) & 0x8) {
401 			/* default output to speakers */
402 			sc->sc_output_mask = 1 << 1;
403 			sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE;
404 			sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER;
405 			awacs_write_codec(sc, sc->sc_codecctl1);
406 		} else {
407 			/* default output to speakers */
408 			sc->sc_output_mask = 1 << 0;
409 			sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
410 			sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE;
411 			awacs_write_codec(sc, sc->sc_codecctl1);
412 		}
413 	}
414 
415 	awacs_write_reg(sc, AWACS_SOUND_CTRL, reason); /* clear interrupt */
416 	return 1;
417 }
418 
419 int
420 awacs_tx_intr(void *v)
421 {
422 	struct awacs_softc *sc = v;
423 	struct dbdma_command *cmd = sc->sc_odmap;
424 	u_int16_t c, status;
425 
426 	/* if not set we are not running */
427 	if (!cmd)
428 		return (0);
429 
430 	c = in16rb(&cmd->d_command);
431 	status = in16rb(&cmd->d_status);
432 
433 	if (c >> 12 == DBDMA_CMD_OUT_LAST)
434 		sc->sc_odmap = sc->sc_odmacmd;
435 	else
436 		sc->sc_odmap++;
437 
438 	if (c & (DBDMA_INT_ALWAYS << 4)) {
439 		cmd->d_status = 0;
440 		if (status)	/* status == 0x8400 */
441 			if (sc->sc_ointr)
442 				(*sc->sc_ointr)(sc->sc_oarg);
443 	}
444 
445 	return (1);
446 }
447 int
448 awacs_rx_intr(void *v)
449 {
450 	struct awacs_softc *sc = v;
451 	struct dbdma_command *cmd = sc->sc_idmap;
452 	u_int16_t c, status;
453 
454 	/* if not set we are not running */
455 	if (!cmd)
456 		return (0);
457 
458 	c = in16rb(&cmd->d_command);
459 	status = in16rb(&cmd->d_status);
460 
461 	if (c >> 12 == DBDMA_CMD_IN_LAST)
462 		sc->sc_idmap = sc->sc_idmacmd;
463 	else
464 		sc->sc_idmap++;
465 
466 	if (c & (DBDMA_INT_ALWAYS << 4)) {
467 		cmd->d_status = 0;
468 		if (status)	/* status == 0x8400 */
469 			if (sc->sc_iintr)
470 				(*sc->sc_iintr)(sc->sc_iarg);
471 	}
472 
473 	return (1);
474 }
475 
476 int
477 awacs_open(void *h, int flags)
478 {
479 	return 0;
480 }
481 
482 /*
483  * Close function is called at splaudio().
484  */
485 void
486 awacs_close(void *h)
487 {
488 	struct awacs_softc *sc = h;
489 
490 	awacs_halt_output(sc);
491 	awacs_halt_input(sc);
492 
493 	sc->sc_ointr = 0;
494 	sc->sc_iintr = 0;
495 }
496 
497 int
498 awacs_query_encoding(void *h, struct audio_encoding *ae)
499 {
500 	switch (ae->index) {
501 	case 0:
502 		strlcpy(ae->name, AudioEslinear, sizeof ae->name);
503 		ae->encoding = AUDIO_ENCODING_SLINEAR;
504 		ae->precision = 16;
505 		ae->flags = 0;
506 		break;
507 	case 1:
508 		strlcpy(ae->name, AudioEslinear_be, sizeof ae->name);
509 		ae->encoding = AUDIO_ENCODING_SLINEAR_BE;
510 		ae->precision = 16;
511 		ae->flags = 0;
512 		break;
513 	case 2:
514 		strlcpy(ae->name, AudioEslinear_le, sizeof ae->name);
515 		ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
516 		ae->precision = 16;
517 		ae->flags = 0;
518 		break;
519 	case 3:
520 		strlcpy(ae->name, AudioEmulaw, sizeof ae->name);
521 		ae->encoding = AUDIO_ENCODING_ULAW;
522 		ae->precision = 8;
523 		ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
524 		break;
525 	case 4:
526 		strlcpy(ae->name, AudioEalaw, sizeof ae->name);
527 		ae->encoding = AUDIO_ENCODING_ALAW;
528 		ae->precision = 8;
529 		ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
530 		break;
531 	case 5:
532 		strlcpy(ae->name, AudioEulinear, sizeof ae->name);
533 		ae->encoding = AUDIO_ENCODING_ULINEAR;
534 		ae->precision = 16;
535 		ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
536 		break;
537 	case 6:
538 		strlcpy(ae->name, AudioEulinear_le, sizeof ae->name);
539 		ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
540 		ae->precision = 16;
541 		ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
542 		break;
543 	case 7:
544 		strlcpy(ae->name, AudioEulinear_be, sizeof ae->name);
545 		ae->encoding = AUDIO_ENCODING_ULINEAR_BE;
546 		ae->precision = 16;
547 		ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
548 		break;
549 	default:
550 		return (EINVAL);
551 	}
552 	ae->bps = AUDIO_BPS(ae->precision);
553 	ae->msb = 1;
554 
555 	return (0);
556 }
557 
558 int
559 awacs_set_params(void *h, int setmode, int usemode, struct audio_params *play,
560     struct audio_params *rec)
561 {
562 	struct awacs_softc *sc = h;
563 	struct audio_params *p;
564 	int mode;
565 
566 	/*
567 	 * This device only has one clock, so make the sample rates match.
568 	 */
569 	if (play->sample_rate != rec->sample_rate &&
570 	    usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
571 		if (setmode == AUMODE_PLAY) {
572 			rec->sample_rate = play->sample_rate;
573 			setmode |= AUMODE_RECORD;
574 		} else if (setmode == AUMODE_RECORD) {
575 			play->sample_rate = rec->sample_rate;
576 			setmode |= AUMODE_PLAY;
577 		} else
578 			return EINVAL;
579 	}
580 
581 	for (mode = AUMODE_RECORD; mode != -1;
582 	     mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
583 		if ((setmode & mode) == 0)
584 			continue;
585 
586 		p = mode == AUMODE_PLAY ? play : rec;
587 
588 		if (p->sample_rate < 4000)
589 			p->sample_rate = 4000;
590 		if (p->sample_rate > 50000)
591 			p->sample_rate = 50000;
592 		if (p->precision > 16)
593 			p->precision = 16;
594 		if (p->channels > 2)
595 			p->channels = 2;
596 
597 		p->factor = 1;
598 		p->sw_code = NULL;
599 		awacs_write_reg(sc, AWACS_BYTE_SWAP, 0);
600 
601 		switch (p->encoding) {
602 
603 		case AUDIO_ENCODING_SLINEAR_LE:
604 			if (p->precision != 16)
605 				p->precision = 16;
606 			if (p->channels == 2)
607 				p->sw_code = swap_bytes;
608 			else {
609 				p->factor = 2;
610 				p->sw_code = swap_bytes_mts;
611 			}
612 			break;
613 		case AUDIO_ENCODING_SLINEAR_BE:
614 			if (p->precision != 16)
615 				p->precision = 16;
616 			if (p->channels == 1) {
617 				p->factor = 2;
618 				p->sw_code = noswap_bytes_mts;
619 			}
620 			break;
621 		case AUDIO_ENCODING_ULINEAR_LE:
622 			if (p->precision != 16)
623 				p->precision = 16;
624 			if (p->channels == 2)
625 				p->sw_code = swap_bytes_change_sign16_be;
626 			else {
627 				p->factor = 2;
628 				p->sw_code = swap_bytes_change_sign16_be_mts;
629 			}
630 			break;
631 		case AUDIO_ENCODING_ULINEAR_BE:
632 			if (p->precision != 16)
633 				p->precision = 16;
634 			if (p->channels == 2)
635 				p->sw_code = change_sign16_be;
636 			else {
637 				p->factor = 2;
638 				p->sw_code = change_sign16_be_mts;
639 			}
640 			break;
641 		case AUDIO_ENCODING_ULAW:
642 			if (mode == AUMODE_PLAY) {
643 				p->factor = 2;
644 				p->sw_code = mulaw_to_slinear16_be;
645 				break;
646 			} else
647 				break;	/* XXX */
648 			return (EINVAL);
649 		case AUDIO_ENCODING_ALAW:
650 			if (mode == AUMODE_PLAY) {
651 				p->factor = 2;
652 				p->sw_code = alaw_to_slinear16_be;
653 				break;
654 			}
655 			return (EINVAL);
656 		default:
657 			return (EINVAL);
658 		}
659 		p->bps = AUDIO_BPS(p->precision);
660 		p->msb = 1;
661 	}
662 
663 	/* Set the speed */
664 	awacs_set_rate(sc, p);
665 
666 	return (0);
667 }
668 
669 int
670 awacs_round_blocksize(void *h, int size)
671 {
672 	if (size < PAGE_SIZE)
673 		size = PAGE_SIZE;
674 	return (size + PAGE_SIZE / 2) & ~(PGOFSET);
675 }
676 
677 int
678 awacs_halt_output(void *h)
679 {
680 	struct awacs_softc *sc = h;
681 
682 	dbdma_stop(sc->sc_odma);
683 	dbdma_reset(sc->sc_odma);
684 	dbdma_stop(sc->sc_odma);
685 	sc->sc_odmap = NULL;
686 	return 0;
687 }
688 
689 int
690 awacs_halt_input(void *h)
691 {
692 	struct awacs_softc *sc = h;
693 
694 	dbdma_stop(sc->sc_idma);
695 	dbdma_reset(sc->sc_idma);
696 	return 0;
697 }
698 
699 int
700 awacs_getdev(void *h, struct audio_device *retp)
701 {
702 	*retp = awacs_device;
703 	return 0;
704 }
705 
706 enum {
707 	AWACS_OUTPUT_SELECT,
708 	AWACS_VOL_SPEAKER,
709 	AWACS_VOL_HEADPHONE,
710 	AWACS_OUTPUT_CLASS,
711 	AWACS_MONITOR_CLASS,
712 	AWACS_INPUT_SELECT,
713 	AWACS_VOL_INPUT,
714 	AWACS_INPUT_CLASS,
715 	AWACS_RECORD_CLASS,
716 	AWACS_ENUM_LAST
717 };
718 
719 int
720 awacs_set_port(void *h, mixer_ctrl_t *mc)
721 {
722 	struct awacs_softc *sc = h;
723 	int l, r;
724 
725 	DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type);
726 
727 	l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
728 	r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
729 
730 	switch (mc->dev) {
731 	case AWACS_OUTPUT_SELECT:
732 		/* no change necessary? */
733 		if (mc->un.mask == sc->sc_output_mask)
734 			return 0;
735 		sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER | AWACS_MUTE_HEADPHONE;
736 		if (mc->un.mask & 1 << 0)
737 			sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
738 		if (mc->un.mask & 1 << 1)
739 			sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE;
740 
741 		awacs_write_codec(sc, sc->sc_codecctl1);
742 		sc->sc_output_mask = mc->un.mask;
743 		return 0;
744 
745 	case AWACS_VOL_SPEAKER:
746 		awacs_set_speaker_volume(sc, l, r);
747 		return 0;
748 
749 	case AWACS_VOL_HEADPHONE:
750 		awacs_set_ext_volume(sc, l, r);
751 		return 0;
752 
753 	case AWACS_VOL_INPUT:
754 		sc->sc_codecctl0 &= ~0xff;
755 		sc->sc_codecctl0 |= (l & 0xf0) | (r >> 4);
756 		awacs_write_codec(sc, sc->sc_codecctl0);
757 		return 0;
758 
759 	case AWACS_INPUT_SELECT:
760 		/* no change necessary? */
761 		if (mc->un.mask == sc->sc_record_source)
762 			return 0;
763 		switch(mc->un.mask) {
764 		case 1<<0: /* CD */
765 			sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
766 			sc->sc_codecctl0 |= AWACS_INPUT_CD;
767 			awacs_write_codec(sc, sc->sc_codecctl0);
768 			break;
769 		case 1<<1: /* microphone */
770 			sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
771 			sc->sc_codecctl0 |= AWACS_INPUT_MICROPHONE;
772 			awacs_write_codec(sc, sc->sc_codecctl0);
773 			break;
774 		case 1<<2: /* line in */
775 			sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
776 			sc->sc_codecctl0 |= AWACS_INPUT_LINE;
777 			awacs_write_codec(sc, sc->sc_codecctl0);
778 			break;
779 		default: /* invalid argument */
780 			return -1;
781 		}
782 		sc->sc_record_source = mc->un.mask;
783 		return 0;
784 	}
785 
786 	return ENXIO;
787 }
788 
789 int
790 awacs_get_port(void *h, mixer_ctrl_t *mc)
791 {
792 	struct awacs_softc *sc = h;
793 	int vol, l, r;
794 
795 	DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type);
796 
797 	switch (mc->dev) {
798 	case AWACS_OUTPUT_SELECT:
799 		mc->un.mask = sc->sc_output_mask;
800 		return 0;
801 
802 	case AWACS_VOL_SPEAKER:
803 		vol = sc->sc_codecctl4;
804 		l = (15 - ((vol & 0x3c0) >> 6)) * 16;
805 		r = (15 - (vol & 0x0f)) * 16;
806 		mc->un.mask = 1 << 0;
807 		mc->un.value.num_channels = 2;
808 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
809 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
810 		return 0;
811 
812 	case AWACS_VOL_HEADPHONE:
813 		vol = sc->sc_codecctl2;
814 		l = (15 - ((vol & 0x3c0) >> 6)) * 16;
815 		r = (15 - (vol & 0x0f)) * 16;
816 		mc->un.mask = 1 << 1;
817 		mc->un.value.num_channels = 2;
818 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
819 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
820 		return 0;
821 
822 	case AWACS_INPUT_SELECT:
823 		mc->un.mask = sc->sc_record_source;
824 		return 0;
825 
826 	case AWACS_VOL_INPUT:
827 		vol = sc->sc_codecctl0 & 0xff;
828 		l = (vol & 0xf0);
829 		r = (vol & 0x0f) << 4;
830 		mc->un.mask = sc->sc_record_source;
831 		mc->un.value.num_channels = 2;
832 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
833 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
834 		return 0;
835 
836 	default:
837 		return ENXIO;
838 	}
839 
840 	return 0;
841 }
842 
843 int
844 awacs_query_devinfo(void *h, mixer_devinfo_t *dip)
845 {
846 	DPRINTF("query_devinfo %d\n", dip->index);
847 
848 	switch (dip->index) {
849 
850 	case AWACS_OUTPUT_SELECT:
851 		dip->mixer_class = AWACS_OUTPUT_CLASS;
852 		strlcpy(dip->label.name, AudioNselect, sizeof dip->label.name);
853 		dip->type = AUDIO_MIXER_SET;
854 		dip->prev = dip->next = AUDIO_MIXER_LAST;
855 		dip->un.s.num_mem = 2;
856 		strlcpy(dip->un.s.member[0].label.name, AudioNspeaker,
857 		    sizeof dip->un.s.member[0].label.name);
858 		dip->un.s.member[0].mask = 1 << 0;
859 		strlcpy(dip->un.s.member[1].label.name, AudioNheadphone,
860 		    sizeof dip->un.s.member[0].label.name);
861 		dip->un.s.member[1].mask = 1 << 1;
862 		return 0;
863 
864 	case AWACS_VOL_SPEAKER:
865 		dip->mixer_class = AWACS_OUTPUT_CLASS;
866 		strlcpy(dip->label.name, AudioNspeaker,
867 		    sizeof dip->label.name);
868 		dip->type = AUDIO_MIXER_VALUE;
869 		dip->prev = dip->next = AUDIO_MIXER_LAST;
870 		dip->un.v.num_channels = 2;
871 		strlcpy(dip->un.v.units.name, AudioNvolume,
872 		    sizeof dip->un.v.units.name);
873 		return 0;
874 
875 	case AWACS_VOL_HEADPHONE:
876 		dip->mixer_class = AWACS_OUTPUT_CLASS;
877 		strlcpy(dip->label.name, AudioNheadphone,
878 		    sizeof dip->label.name);
879 		dip->type = AUDIO_MIXER_VALUE;
880 		dip->prev = dip->next = AUDIO_MIXER_LAST;
881 		dip->un.v.num_channels = 2;
882 		strlcpy(dip->un.v.units.name, AudioNvolume,
883 		    sizeof dip->un.v.units.name);
884 		return 0;
885 
886 	case AWACS_INPUT_SELECT:
887 		dip->mixer_class = AWACS_RECORD_CLASS;
888 		strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
889 		dip->type = AUDIO_MIXER_SET;
890 		dip->prev = dip->next = AUDIO_MIXER_LAST;
891 		dip->un.s.num_mem = 3;
892 		strlcpy(dip->un.s.member[0].label.name, AudioNcd,
893 		    sizeof dip->un.s.member[0].label.name);
894 		dip->un.s.member[0].mask = 1 << 0;
895 		strlcpy(dip->un.s.member[1].label.name, AudioNmicrophone,
896 		    sizeof dip->un.s.member[1].label.name);
897 		dip->un.s.member[1].mask = 1 << 1;
898 		strlcpy(dip->un.s.member[2].label.name, AudioNline,
899 		    sizeof dip->un.s.member[2].label.name);
900 		dip->un.s.member[2].mask = 1 << 2;
901 		return 0;
902 
903 	case AWACS_VOL_INPUT:
904 		dip->mixer_class = AWACS_RECORD_CLASS;
905 		strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
906 		dip->type = AUDIO_MIXER_VALUE;
907 		dip->prev = dip->next = AUDIO_MIXER_LAST;
908 		dip->un.v.num_channels = 2;
909 		strlcpy(dip->un.v.units.name, AudioNvolume,
910 		    sizeof dip->un.v.units.name);
911 		return 0;
912 
913 	case AWACS_MONITOR_CLASS:
914 		dip->mixer_class = AWACS_MONITOR_CLASS;
915 		strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
916 		dip->type = AUDIO_MIXER_CLASS;
917 		dip->next = dip->prev = AUDIO_MIXER_LAST;
918 		return 0;
919 
920 	case AWACS_OUTPUT_CLASS:
921 		dip->mixer_class = AWACS_OUTPUT_CLASS;
922 		strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
923 		dip->type = AUDIO_MIXER_CLASS;
924 		dip->next = dip->prev = AUDIO_MIXER_LAST;
925 		return 0;
926 
927 	case AWACS_RECORD_CLASS:
928 		dip->mixer_class = AWACS_MONITOR_CLASS;
929 		strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
930 		dip->type = AUDIO_MIXER_CLASS;
931 		dip->next = dip->prev = AUDIO_MIXER_LAST;
932 		return 0;
933 	}
934 
935 	return ENXIO;
936 }
937 
938 size_t
939 awacs_round_buffersize(void *h, int dir, size_t size)
940 {
941 	size = (size + PGOFSET) & ~(PGOFSET);
942 	if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX)
943 		size = AWACS_DMALIST_MAX * AWACS_DMASEG_MAX;
944 	return (size);
945 }
946 
947 void *
948 awacs_allocm(void *h, int dir, size_t size, int type, int flags)
949 {
950 	struct awacs_softc *sc = h;
951 	struct awacs_dma *p;
952 	int error;
953 
954 	if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX)
955 		return (NULL);
956 
957 	p = malloc(sizeof(*p), type, flags | M_ZERO);
958 	if (!p)
959 		return (NULL);
960 
961 	/* convert to the bus.h style, not used otherwise */
962 	if (flags & M_NOWAIT)
963 		flags = BUS_DMA_NOWAIT;
964 
965 	p->size = size;
966 	if ((error = bus_dmamem_alloc(sc->sc_dmat, p->size, NBPG, 0, p->segs,
967 	    1, &p->nsegs, flags)) != 0) {
968 		printf("%s: unable to allocate dma, error = %d\n",
969 		    sc->sc_dev.dv_xname, error);
970 		free(p, type);
971 		return NULL;
972 	}
973 
974 	if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size,
975 	    &p->addr, flags | BUS_DMA_COHERENT)) != 0) {
976 		printf("%s: unable to map dma, error = %d\n",
977 		    sc->sc_dev.dv_xname, error);
978 		bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
979 		free(p, type);
980 		return NULL;
981 	}
982 
983 	if ((error = bus_dmamap_create(sc->sc_dmat, p->size, 1,
984 	    p->size, 0, flags, &p->map)) != 0) {
985 		printf("%s: unable to create dma map, error = %d\n",
986 		    sc->sc_dev.dv_xname, error);
987 		bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
988 		bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
989 		free(p, type);
990 		return NULL;
991 	}
992 
993 	if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size,
994 	    NULL, flags)) != 0) {
995 		printf("%s: unable to load dma map, error = %d\n",
996 		    sc->sc_dev.dv_xname, error);
997 		bus_dmamap_destroy(sc->sc_dmat, p->map);
998 		bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
999 		bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
1000 		free(p, type);
1001 		return NULL;
1002 	}
1003 
1004 	p->next = sc->sc_dmas;
1005 	sc->sc_dmas = p;
1006 
1007 	return p->addr;
1008 }
1009 
1010 paddr_t
1011 awacs_mappage(void *h, void *mem, off_t off, int prot)
1012 {
1013 	if (off < 0)
1014 		return -1;
1015 	return -1;	/* XXX */
1016 }
1017 
1018 int
1019 awacs_get_props(void *h)
1020 {
1021 	return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */;
1022 }
1023 
1024 int
1025 awacs_trigger_output(void *h, void *start, void *end, int bsize,
1026     void (*intr)(void *), void *arg, struct audio_params *param)
1027 {
1028 	struct awacs_softc *sc = h;
1029 	struct awacs_dma *p;
1030 	struct dbdma_command *cmd = sc->sc_odmacmd;
1031 	vaddr_t spa, pa, epa;
1032 	int c;
1033 
1034 	DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize);
1035 
1036 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1037 	if (!p)
1038 		return -1;
1039 
1040 	sc->sc_ointr = intr;
1041 	sc->sc_oarg = arg;
1042 	sc->sc_odmap = sc->sc_odmacmd;
1043 
1044 	spa = p->segs[0].ds_addr;
1045 	c = DBDMA_CMD_OUT_MORE;
1046 	for (pa = spa, epa = spa + (end - start);
1047 	    pa < epa; pa += bsize, cmd++) {
1048 
1049 		if (pa + bsize == epa)
1050 			c = DBDMA_CMD_OUT_LAST;
1051 
1052 		DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS,
1053 			DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
1054 	}
1055 
1056 	DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
1057 		DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
1058 	dbdma_st32(&cmd->d_cmddep, sc->sc_odbdma->d_paddr);
1059 
1060 	dbdma_start(sc->sc_odma, sc->sc_odbdma);
1061 
1062 	return 0;
1063 }
1064 
1065 int
1066 awacs_trigger_input(void *h, void *start, void *end, int bsize,
1067     void (*intr)(void *), void *arg, struct audio_params *param)
1068 {
1069 	struct awacs_softc *sc = h;
1070 	struct awacs_dma *p;
1071 	struct dbdma_command *cmd = sc->sc_idmacmd;
1072 	vaddr_t spa, pa, epa;
1073 	int c;
1074 
1075 	DPRINTF("trigger_input %p %p 0x%x\n", start, end, bsize);
1076 
1077 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1078 	if (!p)
1079 		return -1;
1080 
1081 	sc->sc_iintr = intr;
1082 	sc->sc_iarg = arg;
1083 	sc->sc_idmap = sc->sc_idmacmd;
1084 
1085 	spa = p->segs[0].ds_addr;
1086 	c = DBDMA_CMD_IN_MORE;
1087 	for (pa = spa, epa = spa + (end - start);
1088 	    pa < epa; pa += bsize, cmd++) {
1089 
1090 		if (pa + bsize == epa)
1091 			c = DBDMA_CMD_IN_LAST;
1092 
1093 		DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS,
1094 			DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
1095 	}
1096 
1097 	DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
1098 		DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
1099 	dbdma_st32(&cmd->d_cmddep, sc->sc_idbdma->d_paddr);
1100 
1101 	dbdma_start(sc->sc_idma, sc->sc_idbdma);
1102 
1103 	return 0;
1104 }
1105 
1106 void
1107 awacs_set_speaker_volume(struct awacs_softc *sc, int left, int  right)
1108 {
1109 	int lval = 15 - (left  & 0xff) / 16;
1110 	int rval = 15 - (right & 0xff) / 16;
1111 
1112 	DPRINTF("speaker_volume %d %d\n", lval, rval);
1113 
1114 	sc->sc_codecctl4 &= ~0x3cf;
1115 	sc->sc_codecctl4 |= (lval << 6) | rval;
1116 	awacs_write_codec(sc, sc->sc_codecctl4);
1117 }
1118 
1119 void
1120 awacs_set_ext_volume(struct awacs_softc *sc, int left, int  right)
1121 {
1122 	int lval = 15 - (left  & 0xff) / 16;
1123 	int rval = 15 - (right & 0xff) / 16;
1124 
1125 	DPRINTF("ext_volume %d %d\n", lval, rval);
1126 
1127 	sc->sc_codecctl2 &= ~0x3cf;
1128 	sc->sc_codecctl2 |= (lval << 6) | rval;
1129 	awacs_write_codec(sc, sc->sc_codecctl2);
1130 }
1131 
1132 void
1133 awacs_set_rate(struct awacs_softc *sc, struct audio_params *p)
1134 {
1135 	int selected = -1;
1136 	size_t n, i;
1137 
1138 	n = sizeof(awacs_speeds)/sizeof(awacs_speeds[0]);
1139 
1140 	if (p->sample_rate < awacs_speeds[0].rate)
1141 		selected = 0;
1142 	if (p->sample_rate > awacs_speeds[n - 1].rate)
1143 		selected = n - 1;
1144 
1145 	for (i = 1; selected == -1 && i < n; i++) {
1146 		if (p->sample_rate == awacs_speeds[i].rate)
1147 			selected = i;
1148 		else if (p->sample_rate < awacs_speeds[i].rate) {
1149 			u_int diff1, diff2;
1150 
1151 			diff1 = p->sample_rate - awacs_speeds[i - 1].rate;
1152 			diff2 = awacs_speeds[i].rate - p->sample_rate;
1153 			selected = (diff1 < diff2) ? i - 1 : i;
1154 		}
1155 	}
1156 
1157 	if (selected == -1)
1158 		selected = 0;
1159 
1160 	sc->sc_soundctl &= ~AWACS_RATE_MASK;
1161 	sc->sc_soundctl |= awacs_speeds[selected].bits;
1162 	p->sample_rate = awacs_speeds[selected].rate;
1163 	awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
1164 }
1165