xref: /openbsd/sys/arch/macppc/dev/awacs.c (revision 404b540a)
1 /*	$OpenBSD: awacs.c,v 1.24 2008/10/30 06:22:38 todd 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 	return (0);
553 }
554 
555 int
556 awacs_set_params(void *h, int setmode, int usemode, struct audio_params *play,
557     struct audio_params *rec)
558 {
559 	struct awacs_softc *sc = h;
560 	struct audio_params *p;
561 	int mode;
562 
563 	/*
564 	 * This device only has one clock, so make the sample rates match.
565 	 */
566 	if (play->sample_rate != rec->sample_rate &&
567 	    usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
568 		if (setmode == AUMODE_PLAY) {
569 			rec->sample_rate = play->sample_rate;
570 			setmode |= AUMODE_RECORD;
571 		} else if (setmode == AUMODE_RECORD) {
572 			play->sample_rate = rec->sample_rate;
573 			setmode |= AUMODE_PLAY;
574 		} else
575 			return EINVAL;
576 	}
577 
578 	for (mode = AUMODE_RECORD; mode != -1;
579 	     mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
580 		if ((setmode & mode) == 0)
581 			continue;
582 
583 		p = mode == AUMODE_PLAY ? play : rec;
584 
585 		if (p->sample_rate < 4000)
586 			p->sample_rate = 4000;
587 		if (p->sample_rate > 50000)
588 			p->sample_rate = 50000;
589 		if (p->precision > 16)
590 			p->precision = 16;
591 		if (p->channels > 2)
592 			p->channels = 2;
593 
594 		p->factor = 1;
595 		p->sw_code = NULL;
596 		awacs_write_reg(sc, AWACS_BYTE_SWAP, 0);
597 
598 		switch (p->encoding) {
599 
600 		case AUDIO_ENCODING_SLINEAR_LE:
601 			if (p->precision != 16)
602 				p->precision = 16;
603 			if (p->channels == 2)
604 				p->sw_code = swap_bytes;
605 			else {
606 				p->factor = 2;
607 				p->sw_code = swap_bytes_mts;
608 			}
609 			break;
610 		case AUDIO_ENCODING_SLINEAR_BE:
611 			if (p->precision != 16)
612 				p->precision = 16;
613 			if (p->channels == 1) {
614 				p->factor = 2;
615 				p->sw_code = noswap_bytes_mts;
616 			}
617 			break;
618 		case AUDIO_ENCODING_ULINEAR_LE:
619 			if (p->precision != 16)
620 				p->precision = 16;
621 			if (p->channels == 2)
622 				p->sw_code = swap_bytes_change_sign16_be;
623 			else {
624 				p->factor = 2;
625 				p->sw_code = swap_bytes_change_sign16_be_mts;
626 			}
627 			break;
628 		case AUDIO_ENCODING_ULINEAR_BE:
629 			if (p->precision != 16)
630 				p->precision = 16;
631 			if (p->channels == 2)
632 				p->sw_code = change_sign16_be;
633 			else {
634 				p->factor = 2;
635 				p->sw_code = change_sign16_be_mts;
636 			}
637 			break;
638 		case AUDIO_ENCODING_ULAW:
639 			if (mode == AUMODE_PLAY) {
640 				p->factor = 2;
641 				p->sw_code = mulaw_to_slinear16_be;
642 				break;
643 			} else
644 				break;	/* XXX */
645 			return (EINVAL);
646 		case AUDIO_ENCODING_ALAW:
647 			if (mode == AUMODE_PLAY) {
648 				p->factor = 2;
649 				p->sw_code = alaw_to_slinear16_be;
650 				break;
651 			}
652 			return (EINVAL);
653 		default:
654 			return (EINVAL);
655 		}
656 	}
657 
658 	/* Set the speed */
659 	awacs_set_rate(sc, p);
660 
661 	return (0);
662 }
663 
664 int
665 awacs_round_blocksize(void *h, int size)
666 {
667 	if (size < PAGE_SIZE)
668 		size = PAGE_SIZE;
669 	return (size + PAGE_SIZE / 2) & ~(PGOFSET);
670 }
671 
672 int
673 awacs_halt_output(void *h)
674 {
675 	struct awacs_softc *sc = h;
676 
677 	dbdma_stop(sc->sc_odma);
678 	dbdma_reset(sc->sc_odma);
679 	dbdma_stop(sc->sc_odma);
680 	sc->sc_odmap = NULL;
681 	return 0;
682 }
683 
684 int
685 awacs_halt_input(void *h)
686 {
687 	struct awacs_softc *sc = h;
688 
689 	dbdma_stop(sc->sc_idma);
690 	dbdma_reset(sc->sc_idma);
691 	return 0;
692 }
693 
694 int
695 awacs_getdev(void *h, struct audio_device *retp)
696 {
697 	*retp = awacs_device;
698 	return 0;
699 }
700 
701 enum {
702 	AWACS_OUTPUT_SELECT,
703 	AWACS_VOL_SPEAKER,
704 	AWACS_VOL_HEADPHONE,
705 	AWACS_OUTPUT_CLASS,
706 	AWACS_MONITOR_CLASS,
707 	AWACS_INPUT_SELECT,
708 	AWACS_VOL_INPUT,
709 	AWACS_INPUT_CLASS,
710 	AWACS_RECORD_CLASS,
711 	AWACS_ENUM_LAST
712 };
713 
714 int
715 awacs_set_port(void *h, mixer_ctrl_t *mc)
716 {
717 	struct awacs_softc *sc = h;
718 	int l, r;
719 
720 	DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type);
721 
722 	l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
723 	r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
724 
725 	switch (mc->dev) {
726 	case AWACS_OUTPUT_SELECT:
727 		/* no change necessary? */
728 		if (mc->un.mask == sc->sc_output_mask)
729 			return 0;
730 		sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER | AWACS_MUTE_HEADPHONE;
731 		if (mc->un.mask & 1 << 0)
732 			sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
733 		if (mc->un.mask & 1 << 1)
734 			sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE;
735 
736 		awacs_write_codec(sc, sc->sc_codecctl1);
737 		sc->sc_output_mask = mc->un.mask;
738 		return 0;
739 
740 	case AWACS_VOL_SPEAKER:
741 		awacs_set_speaker_volume(sc, l, r);
742 		return 0;
743 
744 	case AWACS_VOL_HEADPHONE:
745 		awacs_set_ext_volume(sc, l, r);
746 		return 0;
747 
748 	case AWACS_VOL_INPUT:
749 		sc->sc_codecctl0 &= ~0xff;
750 		sc->sc_codecctl0 |= (l & 0xf0) | (r >> 4);
751 		awacs_write_codec(sc, sc->sc_codecctl0);
752 		return 0;
753 
754 	case AWACS_INPUT_SELECT:
755 		/* no change necessary? */
756 		if (mc->un.mask == sc->sc_record_source)
757 			return 0;
758 		switch(mc->un.mask) {
759 		case 1<<0: /* CD */
760 			sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
761 			sc->sc_codecctl0 |= AWACS_INPUT_CD;
762 			awacs_write_codec(sc, sc->sc_codecctl0);
763 			break;
764 		case 1<<1: /* microphone */
765 			sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
766 			sc->sc_codecctl0 |= AWACS_INPUT_MICROPHONE;
767 			awacs_write_codec(sc, sc->sc_codecctl0);
768 			break;
769 		case 1<<2: /* line in */
770 			sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
771 			sc->sc_codecctl0 |= AWACS_INPUT_LINE;
772 			awacs_write_codec(sc, sc->sc_codecctl0);
773 			break;
774 		default: /* invalid argument */
775 			return -1;
776 		}
777 		sc->sc_record_source = mc->un.mask;
778 		return 0;
779 	}
780 
781 	return ENXIO;
782 }
783 
784 int
785 awacs_get_port(void *h, mixer_ctrl_t *mc)
786 {
787 	struct awacs_softc *sc = h;
788 	int vol, l, r;
789 
790 	DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type);
791 
792 	switch (mc->dev) {
793 	case AWACS_OUTPUT_SELECT:
794 		mc->un.mask = sc->sc_output_mask;
795 		return 0;
796 
797 	case AWACS_VOL_SPEAKER:
798 		vol = sc->sc_codecctl4;
799 		l = (15 - ((vol & 0x3c0) >> 6)) * 16;
800 		r = (15 - (vol & 0x0f)) * 16;
801 		mc->un.mask = 1 << 0;
802 		mc->un.value.num_channels = 2;
803 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
804 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
805 		return 0;
806 
807 	case AWACS_VOL_HEADPHONE:
808 		vol = sc->sc_codecctl2;
809 		l = (15 - ((vol & 0x3c0) >> 6)) * 16;
810 		r = (15 - (vol & 0x0f)) * 16;
811 		mc->un.mask = 1 << 1;
812 		mc->un.value.num_channels = 2;
813 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
814 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
815 		return 0;
816 
817 	case AWACS_INPUT_SELECT:
818 		mc->un.mask = sc->sc_record_source;
819 		return 0;
820 
821 	case AWACS_VOL_INPUT:
822 		vol = sc->sc_codecctl0 & 0xff;
823 		l = (vol & 0xf0);
824 		r = (vol & 0x0f) << 4;
825 		mc->un.mask = sc->sc_record_source;
826 		mc->un.value.num_channels = 2;
827 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
828 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
829 		return 0;
830 
831 	default:
832 		return ENXIO;
833 	}
834 
835 	return 0;
836 }
837 
838 int
839 awacs_query_devinfo(void *h, mixer_devinfo_t *dip)
840 {
841 	DPRINTF("query_devinfo %d\n", dip->index);
842 
843 	switch (dip->index) {
844 
845 	case AWACS_OUTPUT_SELECT:
846 		dip->mixer_class = AWACS_OUTPUT_CLASS;
847 		strlcpy(dip->label.name, AudioNselect, sizeof dip->label.name);
848 		dip->type = AUDIO_MIXER_SET;
849 		dip->prev = dip->next = AUDIO_MIXER_LAST;
850 		dip->un.s.num_mem = 2;
851 		strlcpy(dip->un.s.member[0].label.name, AudioNspeaker,
852 		    sizeof dip->un.s.member[0].label.name);
853 		dip->un.s.member[0].mask = 1 << 0;
854 		strlcpy(dip->un.s.member[1].label.name, AudioNheadphone,
855 		    sizeof dip->un.s.member[0].label.name);
856 		dip->un.s.member[1].mask = 1 << 1;
857 		return 0;
858 
859 	case AWACS_VOL_SPEAKER:
860 		dip->mixer_class = AWACS_OUTPUT_CLASS;
861 		strlcpy(dip->label.name, AudioNspeaker,
862 		    sizeof dip->label.name);
863 		dip->type = AUDIO_MIXER_VALUE;
864 		dip->prev = dip->next = AUDIO_MIXER_LAST;
865 		dip->un.v.num_channels = 2;
866 		strlcpy(dip->un.v.units.name, AudioNvolume,
867 		    sizeof dip->un.v.units.name);
868 		return 0;
869 
870 	case AWACS_VOL_HEADPHONE:
871 		dip->mixer_class = AWACS_OUTPUT_CLASS;
872 		strlcpy(dip->label.name, AudioNheadphone,
873 		    sizeof dip->label.name);
874 		dip->type = AUDIO_MIXER_VALUE;
875 		dip->prev = dip->next = AUDIO_MIXER_LAST;
876 		dip->un.v.num_channels = 2;
877 		strlcpy(dip->un.v.units.name, AudioNvolume,
878 		    sizeof dip->un.v.units.name);
879 		return 0;
880 
881 	case AWACS_INPUT_SELECT:
882 		dip->mixer_class = AWACS_RECORD_CLASS;
883 		strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
884 		dip->type = AUDIO_MIXER_SET;
885 		dip->prev = dip->next = AUDIO_MIXER_LAST;
886 		dip->un.s.num_mem = 3;
887 		strlcpy(dip->un.s.member[0].label.name, AudioNcd,
888 		    sizeof dip->un.s.member[0].label.name);
889 		dip->un.s.member[0].mask = 1 << 0;
890 		strlcpy(dip->un.s.member[1].label.name, AudioNmicrophone,
891 		    sizeof dip->un.s.member[1].label.name);
892 		dip->un.s.member[1].mask = 1 << 1;
893 		strlcpy(dip->un.s.member[2].label.name, AudioNline,
894 		    sizeof dip->un.s.member[2].label.name);
895 		dip->un.s.member[2].mask = 1 << 2;
896 		return 0;
897 
898 	case AWACS_VOL_INPUT:
899 		dip->mixer_class = AWACS_RECORD_CLASS;
900 		strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
901 		dip->type = AUDIO_MIXER_VALUE;
902 		dip->prev = dip->next = AUDIO_MIXER_LAST;
903 		dip->un.v.num_channels = 2;
904 		strlcpy(dip->un.v.units.name, AudioNvolume,
905 		    sizeof dip->un.v.units.name);
906 		return 0;
907 
908 	case AWACS_MONITOR_CLASS:
909 		dip->mixer_class = AWACS_MONITOR_CLASS;
910 		strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
911 		dip->type = AUDIO_MIXER_CLASS;
912 		dip->next = dip->prev = AUDIO_MIXER_LAST;
913 		return 0;
914 
915 	case AWACS_OUTPUT_CLASS:
916 		dip->mixer_class = AWACS_OUTPUT_CLASS;
917 		strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
918 		dip->type = AUDIO_MIXER_CLASS;
919 		dip->next = dip->prev = AUDIO_MIXER_LAST;
920 		return 0;
921 
922 	case AWACS_RECORD_CLASS:
923 		dip->mixer_class = AWACS_MONITOR_CLASS;
924 		strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
925 		dip->type = AUDIO_MIXER_CLASS;
926 		dip->next = dip->prev = AUDIO_MIXER_LAST;
927 		return 0;
928 	}
929 
930 	return ENXIO;
931 }
932 
933 size_t
934 awacs_round_buffersize(void *h, int dir, size_t size)
935 {
936 	size = (size + PGOFSET) & ~(PGOFSET);
937 	if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX)
938 		size = AWACS_DMALIST_MAX * AWACS_DMASEG_MAX;
939 	return (size);
940 }
941 
942 void *
943 awacs_allocm(void *h, int dir, size_t size, int type, int flags)
944 {
945 	struct awacs_softc *sc = h;
946 	struct awacs_dma *p;
947 	int error;
948 
949 	if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX)
950 		return (NULL);
951 
952 	p = malloc(sizeof(*p), type, flags | M_ZERO);
953 	if (!p)
954 		return (NULL);
955 
956 	/* convert to the bus.h style, not used otherwise */
957 	if (flags & M_NOWAIT)
958 		flags = BUS_DMA_NOWAIT;
959 
960 	p->size = size;
961 	if ((error = bus_dmamem_alloc(sc->sc_dmat, p->size, NBPG, 0, p->segs,
962 	    1, &p->nsegs, flags)) != 0) {
963 		printf("%s: unable to allocate dma, error = %d\n",
964 		    sc->sc_dev.dv_xname, error);
965 		free(p, type);
966 		return NULL;
967 	}
968 
969 	if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size,
970 	    &p->addr, flags | BUS_DMA_COHERENT)) != 0) {
971 		printf("%s: unable to map dma, error = %d\n",
972 		    sc->sc_dev.dv_xname, error);
973 		bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
974 		free(p, type);
975 		return NULL;
976 	}
977 
978 	if ((error = bus_dmamap_create(sc->sc_dmat, p->size, 1,
979 	    p->size, 0, flags, &p->map)) != 0) {
980 		printf("%s: unable to create dma map, error = %d\n",
981 		    sc->sc_dev.dv_xname, error);
982 		bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
983 		bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
984 		free(p, type);
985 		return NULL;
986 	}
987 
988 	if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size,
989 	    NULL, flags)) != 0) {
990 		printf("%s: unable to load dma map, error = %d\n",
991 		    sc->sc_dev.dv_xname, error);
992 		bus_dmamap_destroy(sc->sc_dmat, p->map);
993 		bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
994 		bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
995 		free(p, type);
996 		return NULL;
997 	}
998 
999 	p->next = sc->sc_dmas;
1000 	sc->sc_dmas = p;
1001 
1002 	return p->addr;
1003 }
1004 
1005 paddr_t
1006 awacs_mappage(void *h, void *mem, off_t off, int prot)
1007 {
1008 	if (off < 0)
1009 		return -1;
1010 	return -1;	/* XXX */
1011 }
1012 
1013 int
1014 awacs_get_props(void *h)
1015 {
1016 	return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */;
1017 }
1018 
1019 int
1020 awacs_trigger_output(void *h, void *start, void *end, int bsize,
1021     void (*intr)(void *), void *arg, struct audio_params *param)
1022 {
1023 	struct awacs_softc *sc = h;
1024 	struct awacs_dma *p;
1025 	struct dbdma_command *cmd = sc->sc_odmacmd;
1026 	vaddr_t spa, pa, epa;
1027 	int c;
1028 
1029 	DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize);
1030 
1031 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1032 	if (!p)
1033 		return -1;
1034 
1035 	sc->sc_ointr = intr;
1036 	sc->sc_oarg = arg;
1037 	sc->sc_odmap = sc->sc_odmacmd;
1038 
1039 	spa = p->segs[0].ds_addr;
1040 	c = DBDMA_CMD_OUT_MORE;
1041 	for (pa = spa, epa = spa + (end - start);
1042 	    pa < epa; pa += bsize, cmd++) {
1043 
1044 		if (pa + bsize == epa)
1045 			c = DBDMA_CMD_OUT_LAST;
1046 
1047 		DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS,
1048 			DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
1049 	}
1050 
1051 	DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
1052 		DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
1053 	dbdma_st32(&cmd->d_cmddep, sc->sc_odbdma->d_paddr);
1054 
1055 	dbdma_start(sc->sc_odma, sc->sc_odbdma);
1056 
1057 	return 0;
1058 }
1059 
1060 int
1061 awacs_trigger_input(void *h, void *start, void *end, int bsize,
1062     void (*intr)(void *), void *arg, struct audio_params *param)
1063 {
1064 	struct awacs_softc *sc = h;
1065 	struct awacs_dma *p;
1066 	struct dbdma_command *cmd = sc->sc_idmacmd;
1067 	vaddr_t spa, pa, epa;
1068 	int c;
1069 
1070 	printf("trigger_input %p %p 0x%x\n", start, end, bsize);
1071 
1072 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1073 	if (!p)
1074 		return -1;
1075 
1076 	sc->sc_iintr = intr;
1077 	sc->sc_iarg = arg;
1078 	sc->sc_idmap = sc->sc_idmacmd;
1079 
1080 	spa = p->segs[0].ds_addr;
1081 	c = DBDMA_CMD_IN_MORE;
1082 	for (pa = spa, epa = spa + (end - start);
1083 	    pa < epa; pa += bsize, cmd++) {
1084 
1085 		if (pa + bsize == epa)
1086 			c = DBDMA_CMD_IN_LAST;
1087 
1088 		DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS,
1089 			DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
1090 	}
1091 
1092 	DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
1093 		DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
1094 	dbdma_st32(&cmd->d_cmddep, sc->sc_idbdma->d_paddr);
1095 
1096 	dbdma_start(sc->sc_idma, sc->sc_idbdma);
1097 
1098 	return 0;
1099 }
1100 
1101 void
1102 awacs_set_speaker_volume(struct awacs_softc *sc, int left, int  right)
1103 {
1104 	int lval = 15 - (left  & 0xff) / 16;
1105 	int rval = 15 - (right & 0xff) / 16;
1106 
1107 	DPRINTF("speaker_volume %d %d\n", lval, rval);
1108 
1109 	sc->sc_codecctl4 &= ~0x3cf;
1110 	sc->sc_codecctl4 |= (lval << 6) | rval;
1111 	awacs_write_codec(sc, sc->sc_codecctl4);
1112 }
1113 
1114 void
1115 awacs_set_ext_volume(struct awacs_softc *sc, int left, int  right)
1116 {
1117 	int lval = 15 - (left  & 0xff) / 16;
1118 	int rval = 15 - (right & 0xff) / 16;
1119 
1120 	DPRINTF("ext_volume %d %d\n", lval, rval);
1121 
1122 	sc->sc_codecctl2 &= ~0x3cf;
1123 	sc->sc_codecctl2 |= (lval << 6) | rval;
1124 	awacs_write_codec(sc, sc->sc_codecctl2);
1125 }
1126 
1127 void
1128 awacs_set_rate(struct awacs_softc *sc, struct audio_params *p)
1129 {
1130 	int selected = -1;
1131 	size_t n, i;
1132 
1133 	n = sizeof(awacs_speeds)/sizeof(awacs_speeds[0]);
1134 
1135 	if (p->sample_rate < awacs_speeds[0].rate)
1136 		selected = 0;
1137 	if (p->sample_rate > awacs_speeds[n - 1].rate)
1138 		selected = n - 1;
1139 
1140 	for (i = 1; selected == -1 && i < n; i++) {
1141 		if (p->sample_rate == awacs_speeds[i].rate)
1142 			selected = i;
1143 		else if (p->sample_rate < awacs_speeds[i].rate) {
1144 			u_int diff1, diff2;
1145 
1146 			diff1 = p->sample_rate - awacs_speeds[i - 1].rate;
1147 			diff2 = awacs_speeds[i].rate - p->sample_rate;
1148 			selected = (diff1 < diff2) ? i - 1 : i;
1149 		}
1150 	}
1151 
1152 	if (selected == -1)
1153 		selected = 0;
1154 
1155 	sc->sc_soundctl &= ~AWACS_RATE_MASK;
1156 	sc->sc_soundctl |= awacs_speeds[selected].bits;
1157 	p->sample_rate = awacs_speeds[selected].rate;
1158 	awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
1159 }
1160