awacs.c revision 1.3.2.2 1 1.3.2.2 he /* $NetBSD: awacs.c,v 1.3.2.2 2001/02/04 20:22:48 he Exp $ */
2 1.3.2.2 he
3 1.3.2.2 he /*-
4 1.3.2.2 he * Copyright (c) 2000 Tsubai Masanari. All rights reserved.
5 1.3.2.2 he *
6 1.3.2.2 he * Redistribution and use in source and binary forms, with or without
7 1.3.2.2 he * modification, are permitted provided that the following conditions
8 1.3.2.2 he * are met:
9 1.3.2.2 he * 1. Redistributions of source code must retain the above copyright
10 1.3.2.2 he * notice, this list of conditions and the following disclaimer.
11 1.3.2.2 he * 2. Redistributions in binary form must reproduce the above copyright
12 1.3.2.2 he * notice, this list of conditions and the following disclaimer in the
13 1.3.2.2 he * documentation and/or other materials provided with the distribution.
14 1.3.2.2 he * 3. The name of the author may not be used to endorse or promote products
15 1.3.2.2 he * derived from this software without specific prior written permission.
16 1.3.2.2 he *
17 1.3.2.2 he * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 1.3.2.2 he * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 1.3.2.2 he * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 1.3.2.2 he * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 1.3.2.2 he * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 1.3.2.2 he * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 1.3.2.2 he * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 1.3.2.2 he * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 1.3.2.2 he * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 1.3.2.2 he * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 1.3.2.2 he */
28 1.3.2.2 he
29 1.3.2.2 he #include <sys/param.h>
30 1.3.2.2 he #include <sys/audioio.h>
31 1.3.2.2 he #include <sys/device.h>
32 1.3.2.2 he #include <sys/malloc.h>
33 1.3.2.2 he #include <sys/systm.h>
34 1.3.2.2 he
35 1.3.2.2 he #include <dev/auconv.h>
36 1.3.2.2 he #include <dev/audio_if.h>
37 1.3.2.2 he #include <dev/mulaw.h>
38 1.3.2.2 he
39 1.3.2.2 he #include <uvm/uvm_extern.h>
40 1.3.2.2 he
41 1.3.2.2 he #include <machine/autoconf.h>
42 1.3.2.2 he #include <machine/pio.h>
43 1.3.2.2 he #include <macppc/dev/dbdma.h>
44 1.3.2.2 he
45 1.3.2.2 he #ifdef AWACS_DEBUG
46 1.3.2.2 he # define DPRINTF printf
47 1.3.2.2 he #else
48 1.3.2.2 he # define DPRINTF while (0) printf
49 1.3.2.2 he #endif
50 1.3.2.2 he
51 1.3.2.2 he struct awacs_softc {
52 1.3.2.2 he struct device sc_dev;
53 1.3.2.2 he
54 1.3.2.2 he void (*sc_ointr)(void *); /* dma completion intr handler */
55 1.3.2.2 he void *sc_oarg; /* arg for sc_ointr() */
56 1.3.2.2 he int sc_opages; /* # of output pages */
57 1.3.2.2 he
58 1.3.2.2 he void (*sc_iintr)(void *); /* dma completion intr handler */
59 1.3.2.2 he void *sc_iarg; /* arg for sc_iintr() */
60 1.3.2.2 he
61 1.3.2.2 he u_int sc_record_source; /* recording source mask */
62 1.3.2.2 he u_int sc_output_mask; /* output source mask */
63 1.3.2.2 he
64 1.3.2.2 he char *sc_reg;
65 1.3.2.2 he u_int sc_codecctl0;
66 1.3.2.2 he u_int sc_codecctl1;
67 1.3.2.2 he u_int sc_codecctl2;
68 1.3.2.2 he u_int sc_codecctl4;
69 1.3.2.2 he u_int sc_soundctl;
70 1.3.2.2 he
71 1.3.2.2 he struct dbdma_regmap *sc_odma;
72 1.3.2.2 he struct dbdma_regmap *sc_idma;
73 1.3.2.2 he struct dbdma_command *sc_odmacmd;
74 1.3.2.2 he struct dbdma_command *sc_idmacmd;
75 1.3.2.2 he };
76 1.3.2.2 he
77 1.3.2.2 he int awacs_match(struct device *, struct cfdata *, void *);
78 1.3.2.2 he void awacs_attach(struct device *, struct device *, void *);
79 1.3.2.2 he int awacs_intr(void *);
80 1.3.2.2 he
81 1.3.2.2 he int awacs_open(void *, int);
82 1.3.2.2 he void awacs_close(void *);
83 1.3.2.2 he int awacs_query_encoding(void *, struct audio_encoding *);
84 1.3.2.2 he int awacs_set_params(void *, int, int, struct audio_params *,
85 1.3.2.2 he struct audio_params *);
86 1.3.2.2 he int awacs_round_blocksize(void *, int);
87 1.3.2.2 he int awacs_trigger_output(void *, void *, void *, int, void (*)(void *),
88 1.3.2.2 he void *, struct audio_params *);
89 1.3.2.2 he int awacs_trigger_input(void *, void *, void *, int, void (*)(void *),
90 1.3.2.2 he void *, struct audio_params *);
91 1.3.2.2 he int awacs_halt_output(void *);
92 1.3.2.2 he int awacs_halt_input(void *);
93 1.3.2.2 he int awacs_getdev(void *, struct audio_device *);
94 1.3.2.2 he int awacs_set_port(void *, mixer_ctrl_t *);
95 1.3.2.2 he int awacs_get_port(void *, mixer_ctrl_t *);
96 1.3.2.2 he int awacs_query_devinfo(void *, mixer_devinfo_t *);
97 1.3.2.2 he size_t awacs_round_buffersize(void *, int, size_t);
98 1.3.2.2 he paddr_t awacs_mappage(void *, void *, off_t, int);
99 1.3.2.2 he int awacs_get_props(void *);
100 1.3.2.2 he
101 1.3.2.2 he static inline u_int awacs_read_reg(struct awacs_softc *, int);
102 1.3.2.2 he static inline void awacs_write_reg(struct awacs_softc *, int, int);
103 1.3.2.2 he void awacs_write_codec(struct awacs_softc *, int);
104 1.3.2.2 he void awacs_set_speaker_volume(struct awacs_softc *, int, int);
105 1.3.2.2 he void awacs_set_ext_volume(struct awacs_softc *, int, int);
106 1.3.2.2 he int awacs_set_rate(struct awacs_softc *, int);
107 1.3.2.2 he
108 1.3.2.2 he struct cfattach awacs_ca = {
109 1.3.2.2 he sizeof(struct awacs_softc), awacs_match, awacs_attach
110 1.3.2.2 he };
111 1.3.2.2 he
112 1.3.2.2 he struct audio_hw_if awacs_hw_if = {
113 1.3.2.2 he awacs_open,
114 1.3.2.2 he awacs_close,
115 1.3.2.2 he NULL,
116 1.3.2.2 he awacs_query_encoding,
117 1.3.2.2 he awacs_set_params,
118 1.3.2.2 he awacs_round_blocksize,
119 1.3.2.2 he NULL,
120 1.3.2.2 he NULL,
121 1.3.2.2 he NULL,
122 1.3.2.2 he NULL,
123 1.3.2.2 he NULL,
124 1.3.2.2 he awacs_halt_output,
125 1.3.2.2 he awacs_halt_input,
126 1.3.2.2 he NULL,
127 1.3.2.2 he awacs_getdev,
128 1.3.2.2 he NULL,
129 1.3.2.2 he awacs_set_port,
130 1.3.2.2 he awacs_get_port,
131 1.3.2.2 he awacs_query_devinfo,
132 1.3.2.2 he NULL,
133 1.3.2.2 he NULL,
134 1.3.2.2 he awacs_round_buffersize,
135 1.3.2.2 he awacs_mappage,
136 1.3.2.2 he awacs_get_props,
137 1.3.2.2 he awacs_trigger_output,
138 1.3.2.2 he awacs_trigger_input,
139 1.3.2.2 he };
140 1.3.2.2 he
141 1.3.2.2 he struct audio_device awacs_device = {
142 1.3.2.2 he "AWACS",
143 1.3.2.2 he "",
144 1.3.2.2 he "awacs"
145 1.3.2.2 he };
146 1.3.2.2 he
147 1.3.2.2 he /* register offset */
148 1.3.2.2 he #define AWACS_SOUND_CTRL 0x00
149 1.3.2.2 he #define AWACS_CODEC_CTRL 0x10
150 1.3.2.2 he #define AWACS_CODEC_STATUS 0x20
151 1.3.2.2 he #define AWACS_CLIP_COUNT 0x30
152 1.3.2.2 he #define AWACS_BYTE_SWAP 0x40
153 1.3.2.2 he
154 1.3.2.2 he /* sound control */
155 1.3.2.2 he #define AWACS_INPUT_SUBFRAME0 0x00000001
156 1.3.2.2 he #define AWACS_INPUT_SUBFRAME1 0x00000002
157 1.3.2.2 he #define AWACS_INPUT_SUBFRAME2 0x00000004
158 1.3.2.2 he #define AWACS_INPUT_SUBFRAME3 0x00000008
159 1.3.2.2 he
160 1.3.2.2 he #define AWACS_OUTPUT_SUBFRAME0 0x00000010
161 1.3.2.2 he #define AWACS_OUTPUT_SUBFRAME1 0x00000020
162 1.3.2.2 he #define AWACS_OUTPUT_SUBFRAME2 0x00000040
163 1.3.2.2 he #define AWACS_OUTPUT_SUBFRAME3 0x00000080
164 1.3.2.2 he
165 1.3.2.2 he #define AWACS_RATE_44100 0x00000000
166 1.3.2.2 he #define AWACS_RATE_29400 0x00000100
167 1.3.2.2 he #define AWACS_RATE_22050 0x00000200
168 1.3.2.2 he #define AWACS_RATE_17640 0x00000300
169 1.3.2.2 he #define AWACS_RATE_14700 0x00000400
170 1.3.2.2 he #define AWACS_RATE_11025 0x00000500
171 1.3.2.2 he #define AWACS_RATE_8820 0x00000600
172 1.3.2.2 he #define AWACS_RATE_7350 0x00000700
173 1.3.2.2 he #define AWACS_RATE_MASK 0x00000700
174 1.3.2.2 he
175 1.3.2.2 he /* codec control */
176 1.3.2.2 he #define AWACS_CODEC_ADDR0 0x00000000
177 1.3.2.2 he #define AWACS_CODEC_ADDR1 0x00001000
178 1.3.2.2 he #define AWACS_CODEC_ADDR2 0x00002000
179 1.3.2.2 he #define AWACS_CODEC_ADDR4 0x00004000
180 1.3.2.2 he #define AWACS_CODEC_EMSEL0 0x00000000
181 1.3.2.2 he #define AWACS_CODEC_EMSEL1 0x00400000
182 1.3.2.2 he #define AWACS_CODEC_EMSEL2 0x00800000
183 1.3.2.2 he #define AWACS_CODEC_EMSEL4 0x00c00000
184 1.3.2.2 he #define AWACS_CODEC_BUSY 0x01000000
185 1.3.2.2 he
186 1.3.2.2 he /* cc0 */
187 1.3.2.2 he #define AWACS_DEFAULT_CD_GAIN 0x000000bb
188 1.3.2.2 he #define AWACS_INPUT_CD 0x00000200
189 1.3.2.2 he #define AWACS_INPUT_MIC 0x00000400
190 1.3.2.2 he #define AWACS_INPUT_MASK 0x00000e00
191 1.3.2.2 he
192 1.3.2.2 he /* cc1 */
193 1.3.2.2 he #define AWACS_MUTE_SPEAKER 0x00000080
194 1.3.2.2 he #define AWACS_MUTE_HEADPHONE 0x00000200
195 1.3.2.2 he
196 1.3.2.2 he int
197 1.3.2.2 he awacs_match(parent, match, aux)
198 1.3.2.2 he struct device *parent;
199 1.3.2.2 he struct cfdata *match;
200 1.3.2.2 he void *aux;
201 1.3.2.2 he {
202 1.3.2.2 he struct confargs *ca = aux;
203 1.3.2.2 he
204 1.3.2.2 he if (strcmp(ca->ca_name, "awacs") != 0 &&
205 1.3.2.2 he strcmp(ca->ca_name, "davbus") != 0)
206 1.3.2.2 he return 0;
207 1.3.2.2 he
208 1.3.2.2 he if (ca->ca_nreg < 24 || ca->ca_nintr < 12)
209 1.3.2.2 he return 0;
210 1.3.2.2 he
211 1.3.2.2 he return 1;
212 1.3.2.2 he }
213 1.3.2.2 he
214 1.3.2.2 he void
215 1.3.2.2 he awacs_attach(parent, self, aux)
216 1.3.2.2 he struct device *parent;
217 1.3.2.2 he struct device *self;
218 1.3.2.2 he void *aux;
219 1.3.2.2 he {
220 1.3.2.2 he struct awacs_softc *sc = (struct awacs_softc *)self;
221 1.3.2.2 he struct confargs *ca = aux;
222 1.3.2.2 he
223 1.3.2.2 he ca->ca_reg[0] += ca->ca_baseaddr;
224 1.3.2.2 he ca->ca_reg[2] += ca->ca_baseaddr;
225 1.3.2.2 he ca->ca_reg[4] += ca->ca_baseaddr;
226 1.3.2.2 he
227 1.3.2.2 he sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1]);
228 1.3.2.2 he
229 1.3.2.2 he sc->sc_odma = mapiodev(ca->ca_reg[2], ca->ca_reg[3]); /* out */
230 1.3.2.2 he sc->sc_idma = mapiodev(ca->ca_reg[4], ca->ca_reg[5]); /* in */
231 1.3.2.2 he sc->sc_odmacmd = dbdma_alloc(20 * sizeof(struct dbdma_command));
232 1.3.2.2 he sc->sc_idmacmd = dbdma_alloc(20 * sizeof(struct dbdma_command));
233 1.3.2.2 he
234 1.3.2.2 he intr_establish(ca->ca_intr[0], IST_LEVEL, IPL_AUDIO, awacs_intr, sc);
235 1.3.2.2 he intr_establish(ca->ca_intr[1], IST_LEVEL, IPL_AUDIO, awacs_intr, sc);
236 1.3.2.2 he intr_establish(ca->ca_intr[2], IST_LEVEL, IPL_AUDIO, awacs_intr, sc);
237 1.3.2.2 he
238 1.3.2.2 he printf(": irq %d,%d,%d\n",
239 1.3.2.2 he ca->ca_intr[0], ca->ca_intr[1], ca->ca_intr[2]);
240 1.3.2.2 he
241 1.3.2.2 he sc->sc_soundctl = AWACS_INPUT_SUBFRAME0 | AWACS_OUTPUT_SUBFRAME0 |
242 1.3.2.2 he AWACS_RATE_44100;
243 1.3.2.2 he awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
244 1.3.2.2 he
245 1.3.2.2 he sc->sc_codecctl0 = AWACS_CODEC_ADDR0 | AWACS_CODEC_EMSEL0;
246 1.3.2.2 he sc->sc_codecctl1 = AWACS_CODEC_ADDR1 | AWACS_CODEC_EMSEL0;
247 1.3.2.2 he sc->sc_codecctl2 = AWACS_CODEC_ADDR2 | AWACS_CODEC_EMSEL0;
248 1.3.2.2 he sc->sc_codecctl4 = AWACS_CODEC_ADDR4 | AWACS_CODEC_EMSEL0;
249 1.3.2.2 he
250 1.3.2.2 he sc->sc_codecctl0 |= AWACS_INPUT_CD | AWACS_DEFAULT_CD_GAIN;
251 1.3.2.2 he awacs_write_codec(sc, sc->sc_codecctl0);
252 1.3.2.2 he
253 1.3.2.2 he /* Set initial volume[s] */
254 1.3.2.2 he awacs_set_speaker_volume(sc, 80, 80);
255 1.3.2.2 he
256 1.3.2.2 he /* Set loopback (for CD?) */
257 1.3.2.2 he sc->sc_codecctl1 |= 0x440;
258 1.3.2.2 he awacs_write_codec(sc, sc->sc_codecctl1);
259 1.3.2.2 he
260 1.3.2.2 he sc->sc_output_mask = 1 << 0;
261 1.3.2.2 he
262 1.3.2.2 he sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
263 1.3.2.2 he sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE;
264 1.3.2.2 he awacs_write_codec(sc, sc->sc_codecctl1);
265 1.3.2.2 he
266 1.3.2.2 he /* Enable interrupts and looping mode. */
267 1.3.2.2 he /* XXX ... */
268 1.3.2.2 he
269 1.3.2.2 he audio_attach_mi(&awacs_hw_if, sc, &sc->sc_dev);
270 1.3.2.2 he }
271 1.3.2.2 he
272 1.3.2.2 he u_int
273 1.3.2.2 he awacs_read_reg(sc, reg)
274 1.3.2.2 he struct awacs_softc *sc;
275 1.3.2.2 he int reg;
276 1.3.2.2 he {
277 1.3.2.2 he char *addr = sc->sc_reg;
278 1.3.2.2 he
279 1.3.2.2 he return in32rb(addr + reg);
280 1.3.2.2 he }
281 1.3.2.2 he
282 1.3.2.2 he void
283 1.3.2.2 he awacs_write_reg(sc, reg, val)
284 1.3.2.2 he struct awacs_softc *sc;
285 1.3.2.2 he int reg, val;
286 1.3.2.2 he {
287 1.3.2.2 he char *addr = sc->sc_reg;
288 1.3.2.2 he
289 1.3.2.2 he out32rb(addr + reg, val);
290 1.3.2.2 he }
291 1.3.2.2 he
292 1.3.2.2 he void
293 1.3.2.2 he awacs_write_codec(sc, value)
294 1.3.2.2 he struct awacs_softc *sc;
295 1.3.2.2 he int value;
296 1.3.2.2 he {
297 1.3.2.2 he awacs_write_reg(sc, AWACS_CODEC_CTRL, value);
298 1.3.2.2 he while (awacs_read_reg(sc, AWACS_CODEC_CTRL) & AWACS_CODEC_BUSY);
299 1.3.2.2 he }
300 1.3.2.2 he
301 1.3.2.2 he int
302 1.3.2.2 he awacs_intr(v)
303 1.3.2.2 he void *v;
304 1.3.2.2 he {
305 1.3.2.2 he struct awacs_softc *sc = v;
306 1.3.2.2 he struct dbdma_command *cmd = sc->sc_odmacmd;
307 1.3.2.2 he int count = sc->sc_opages;
308 1.3.2.2 he int status;
309 1.3.2.2 he
310 1.3.2.2 he /* Fill used buffer(s). */
311 1.3.2.2 he while (count-- > 0) {
312 1.3.2.2 he /* if DBDMA_INT_ALWAYS */
313 1.3.2.2 he if (in16rb(&cmd->d_command) & 0x30) { /* XXX */
314 1.3.2.2 he status = in16rb(&cmd->d_status);
315 1.3.2.2 he cmd->d_status = 0;
316 1.3.2.2 he if (status) /* status == 0x8400 */
317 1.3.2.2 he if (sc->sc_ointr)
318 1.3.2.2 he (*sc->sc_ointr)(sc->sc_oarg);
319 1.3.2.2 he }
320 1.3.2.2 he cmd++;
321 1.3.2.2 he }
322 1.3.2.2 he
323 1.3.2.2 he return 1;
324 1.3.2.2 he }
325 1.3.2.2 he
326 1.3.2.2 he int
327 1.3.2.2 he awacs_open(h, flags)
328 1.3.2.2 he void *h;
329 1.3.2.2 he int flags;
330 1.3.2.2 he {
331 1.3.2.2 he return 0;
332 1.3.2.2 he }
333 1.3.2.2 he
334 1.3.2.2 he /*
335 1.3.2.2 he * Close function is called at splaudio().
336 1.3.2.2 he */
337 1.3.2.2 he void
338 1.3.2.2 he awacs_close(h)
339 1.3.2.2 he void *h;
340 1.3.2.2 he {
341 1.3.2.2 he struct awacs_softc *sc = h;
342 1.3.2.2 he
343 1.3.2.2 he awacs_halt_output(sc);
344 1.3.2.2 he awacs_halt_input(sc);
345 1.3.2.2 he
346 1.3.2.2 he sc->sc_ointr = 0;
347 1.3.2.2 he sc->sc_iintr = 0;
348 1.3.2.2 he }
349 1.3.2.2 he
350 1.3.2.2 he int
351 1.3.2.2 he awacs_query_encoding(h, ae)
352 1.3.2.2 he void *h;
353 1.3.2.2 he struct audio_encoding *ae;
354 1.3.2.2 he {
355 1.3.2.2 he switch (ae->index) {
356 1.3.2.2 he case 0:
357 1.3.2.2 he strcpy(ae->name, AudioEslinear);
358 1.3.2.2 he ae->encoding = AUDIO_ENCODING_SLINEAR;
359 1.3.2.2 he ae->precision = 16;
360 1.3.2.2 he ae->flags = 0;
361 1.3.2.2 he return 0;
362 1.3.2.2 he case 1:
363 1.3.2.2 he strcpy(ae->name, AudioEslinear_be);
364 1.3.2.2 he ae->encoding = AUDIO_ENCODING_SLINEAR_BE;
365 1.3.2.2 he ae->precision = 16;
366 1.3.2.2 he ae->flags = 0;
367 1.3.2.2 he return 0;
368 1.3.2.2 he case 2:
369 1.3.2.2 he strcpy(ae->name, AudioEslinear_le);
370 1.3.2.2 he ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
371 1.3.2.2 he ae->precision = 16;
372 1.3.2.2 he ae->flags = 0;
373 1.3.2.2 he return 0;
374 1.3.2.2 he case 3:
375 1.3.2.2 he strcpy(ae->name, AudioEmulaw);
376 1.3.2.2 he ae->encoding = AUDIO_ENCODING_ULAW;
377 1.3.2.2 he ae->precision = 8;
378 1.3.2.2 he ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
379 1.3.2.2 he return 0;
380 1.3.2.2 he case 4:
381 1.3.2.2 he strcpy(ae->name, AudioEalaw);
382 1.3.2.2 he ae->encoding = AUDIO_ENCODING_ALAW;
383 1.3.2.2 he ae->precision = 8;
384 1.3.2.2 he ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
385 1.3.2.2 he return 0;
386 1.3.2.2 he default:
387 1.3.2.2 he return EINVAL;
388 1.3.2.2 he }
389 1.3.2.2 he }
390 1.3.2.2 he
391 1.3.2.2 he static void
392 1.3.2.2 he mono16_to_stereo16(v, p, cc)
393 1.3.2.2 he void *v;
394 1.3.2.2 he u_char *p;
395 1.3.2.2 he int cc;
396 1.3.2.2 he {
397 1.3.2.2 he int x;
398 1.3.2.2 he int16_t *src, *dst;
399 1.3.2.2 he
400 1.3.2.2 he src = (void *)(p + cc);
401 1.3.2.2 he dst = (void *)(p + cc * 2);
402 1.3.2.2 he while (cc > 0) {
403 1.3.2.2 he x = *--src;
404 1.3.2.2 he *--dst = x;
405 1.3.2.2 he *--dst = x;
406 1.3.2.2 he cc -= 2;
407 1.3.2.2 he }
408 1.3.2.2 he }
409 1.3.2.2 he
410 1.3.2.2 he int
411 1.3.2.2 he awacs_set_params(h, setmode, usemode, play, rec)
412 1.3.2.2 he void *h;
413 1.3.2.2 he int setmode, usemode;
414 1.3.2.2 he struct audio_params *play, *rec;
415 1.3.2.2 he {
416 1.3.2.2 he struct awacs_softc *sc = h;
417 1.3.2.2 he struct audio_params *p;
418 1.3.2.2 he int mode, rate;
419 1.3.2.2 he
420 1.3.2.2 he /*
421 1.3.2.2 he * This device only has one clock, so make the sample rates match.
422 1.3.2.2 he */
423 1.3.2.2 he if (play->sample_rate != rec->sample_rate &&
424 1.3.2.2 he usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
425 1.3.2.2 he if (setmode == AUMODE_PLAY) {
426 1.3.2.2 he rec->sample_rate = play->sample_rate;
427 1.3.2.2 he setmode |= AUMODE_RECORD;
428 1.3.2.2 he } else if (setmode == AUMODE_RECORD) {
429 1.3.2.2 he play->sample_rate = rec->sample_rate;
430 1.3.2.2 he setmode |= AUMODE_PLAY;
431 1.3.2.2 he } else
432 1.3.2.2 he return EINVAL;
433 1.3.2.2 he }
434 1.3.2.2 he
435 1.3.2.2 he for (mode = AUMODE_RECORD; mode != -1;
436 1.3.2.2 he mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
437 1.3.2.2 he if ((setmode & mode) == 0)
438 1.3.2.2 he continue;
439 1.3.2.2 he
440 1.3.2.2 he p = mode == AUMODE_PLAY ? play : rec;
441 1.3.2.2 he
442 1.3.2.2 he if (p->sample_rate < 4000 || p->sample_rate > 50000 ||
443 1.3.2.2 he (p->precision != 8 && p->precision != 16) ||
444 1.3.2.2 he (p->channels != 1 && p->channels != 2))
445 1.3.2.2 he return EINVAL;
446 1.3.2.2 he
447 1.3.2.2 he p->factor = 1;
448 1.3.2.2 he p->sw_code = 0;
449 1.3.2.2 he awacs_write_reg(sc, AWACS_BYTE_SWAP, 0);
450 1.3.2.2 he
451 1.3.2.2 he switch (p->encoding) {
452 1.3.2.2 he
453 1.3.2.2 he case AUDIO_ENCODING_SLINEAR_LE:
454 1.3.2.2 he awacs_write_reg(sc, AWACS_BYTE_SWAP, 1);
455 1.3.2.2 he case AUDIO_ENCODING_SLINEAR_BE:
456 1.3.2.2 he if (p->channels == 1) {
457 1.3.2.2 he p->factor = 2;
458 1.3.2.2 he p->sw_code = mono16_to_stereo16;
459 1.3.2.2 he break;
460 1.3.2.2 he }
461 1.3.2.2 he if (p->precision != 16)
462 1.3.2.2 he return EINVAL;
463 1.3.2.2 he /* p->sw_code = change_sign8; */
464 1.3.2.2 he break;
465 1.3.2.2 he
466 1.3.2.2 he case AUDIO_ENCODING_ULINEAR_LE:
467 1.3.2.2 he awacs_write_reg(sc, AWACS_BYTE_SWAP, 1);
468 1.3.2.2 he case AUDIO_ENCODING_ULINEAR_BE:
469 1.3.2.2 he if (p->precision == 16)
470 1.3.2.2 he p->sw_code = change_sign16_be;
471 1.3.2.2 he else
472 1.3.2.2 he return EINVAL;
473 1.3.2.2 he break;
474 1.3.2.2 he
475 1.3.2.2 he case AUDIO_ENCODING_ULAW:
476 1.3.2.2 he if (mode == AUMODE_PLAY) {
477 1.3.2.2 he p->factor = 2;
478 1.3.2.2 he p->sw_code = mulaw_to_slinear16_be;
479 1.3.2.2 he } else
480 1.3.2.2 he p->sw_code = ulinear8_to_mulaw;
481 1.3.2.2 he break;
482 1.3.2.2 he
483 1.3.2.2 he case AUDIO_ENCODING_ALAW:
484 1.3.2.2 he if (mode == AUMODE_PLAY) {
485 1.3.2.2 he p->factor = 2;
486 1.3.2.2 he p->sw_code = alaw_to_slinear16_be;
487 1.3.2.2 he } else
488 1.3.2.2 he p->sw_code = ulinear8_to_alaw;
489 1.3.2.2 he break;
490 1.3.2.2 he
491 1.3.2.2 he default:
492 1.3.2.2 he return EINVAL;
493 1.3.2.2 he }
494 1.3.2.2 he }
495 1.3.2.2 he
496 1.3.2.2 he /* Set the speed */
497 1.3.2.2 he rate = p->sample_rate;
498 1.3.2.2 he
499 1.3.2.2 he awacs_set_rate(sc, rate);
500 1.3.2.2 he
501 1.3.2.2 he return 0;
502 1.3.2.2 he }
503 1.3.2.2 he
504 1.3.2.2 he int
505 1.3.2.2 he awacs_round_blocksize(h, size)
506 1.3.2.2 he void *h;
507 1.3.2.2 he int size;
508 1.3.2.2 he {
509 1.3.2.2 he return size & ~PGOFSET;
510 1.3.2.2 he }
511 1.3.2.2 he
512 1.3.2.2 he int
513 1.3.2.2 he awacs_halt_output(h)
514 1.3.2.2 he void *h;
515 1.3.2.2 he {
516 1.3.2.2 he struct awacs_softc *sc = h;
517 1.3.2.2 he
518 1.3.2.2 he dbdma_stop(sc->sc_odma);
519 1.3.2.2 he dbdma_reset(sc->sc_odma);
520 1.3.2.2 he return 0;
521 1.3.2.2 he }
522 1.3.2.2 he
523 1.3.2.2 he int
524 1.3.2.2 he awacs_halt_input(h)
525 1.3.2.2 he void *h;
526 1.3.2.2 he {
527 1.3.2.2 he struct awacs_softc *sc = h;
528 1.3.2.2 he
529 1.3.2.2 he dbdma_stop(sc->sc_idma);
530 1.3.2.2 he dbdma_reset(sc->sc_idma);
531 1.3.2.2 he return 0;
532 1.3.2.2 he }
533 1.3.2.2 he
534 1.3.2.2 he int
535 1.3.2.2 he awacs_getdev(h, retp)
536 1.3.2.2 he void *h;
537 1.3.2.2 he struct audio_device *retp;
538 1.3.2.2 he {
539 1.3.2.2 he *retp = awacs_device;
540 1.3.2.2 he return 0;
541 1.3.2.2 he }
542 1.3.2.2 he
543 1.3.2.2 he enum {
544 1.3.2.2 he AWACS_OUTPUT_SELECT,
545 1.3.2.2 he AWACS_VOL_SPEAKER,
546 1.3.2.2 he AWACS_VOL_HEADPHONE,
547 1.3.2.2 he AWACS_OUTPUT_CLASS,
548 1.3.2.2 he AWACS_MONITOR_CLASS,
549 1.3.2.2 he AWACS_ENUM_LAST
550 1.3.2.2 he };
551 1.3.2.2 he
552 1.3.2.2 he int
553 1.3.2.2 he awacs_set_port(h, mc)
554 1.3.2.2 he void *h;
555 1.3.2.2 he mixer_ctrl_t *mc;
556 1.3.2.2 he {
557 1.3.2.2 he struct awacs_softc *sc = h;
558 1.3.2.2 he int l, r;
559 1.3.2.2 he
560 1.3.2.2 he DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type);
561 1.3.2.2 he
562 1.3.2.2 he l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
563 1.3.2.2 he r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
564 1.3.2.2 he
565 1.3.2.2 he switch (mc->dev) {
566 1.3.2.2 he case AWACS_OUTPUT_SELECT:
567 1.3.2.2 he printf("output_select mask = 0x%x\n", mc->un.mask);
568 1.3.2.2 he sc->sc_output_mask = mc->un.mask;
569 1.3.2.2 he return 0;
570 1.3.2.2 he
571 1.3.2.2 he case AWACS_VOL_SPEAKER:
572 1.3.2.2 he awacs_set_speaker_volume(sc, l, r);
573 1.3.2.2 he return 0;
574 1.3.2.2 he
575 1.3.2.2 he case AWACS_VOL_HEADPHONE:
576 1.3.2.2 he awacs_set_ext_volume(sc, l, r);
577 1.3.2.2 he return 0;
578 1.3.2.2 he }
579 1.3.2.2 he
580 1.3.2.2 he return ENXIO;
581 1.3.2.2 he }
582 1.3.2.2 he
583 1.3.2.2 he int
584 1.3.2.2 he awacs_get_port(h, mc)
585 1.3.2.2 he void *h;
586 1.3.2.2 he mixer_ctrl_t *mc;
587 1.3.2.2 he {
588 1.3.2.2 he struct awacs_softc *sc = h;
589 1.3.2.2 he int vol, l, r;
590 1.3.2.2 he
591 1.3.2.2 he DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type);
592 1.3.2.2 he
593 1.3.2.2 he switch (mc->dev) {
594 1.3.2.2 he case AWACS_OUTPUT_SELECT:
595 1.3.2.2 he mc->un.mask = sc->sc_output_mask;
596 1.3.2.2 he return 0;
597 1.3.2.2 he
598 1.3.2.2 he case AWACS_VOL_SPEAKER:
599 1.3.2.2 he vol = sc->sc_codecctl4;
600 1.3.2.2 he l = (15 - ((vol & 0x3c0) >> 6)) * 16;
601 1.3.2.2 he r = (15 - (vol & 0x0f)) * 16;
602 1.3.2.2 he mc->un.mask = 1 << 0;
603 1.3.2.2 he mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
604 1.3.2.2 he mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
605 1.3.2.2 he return 0;
606 1.3.2.2 he
607 1.3.2.2 he case AWACS_VOL_HEADPHONE:
608 1.3.2.2 he vol = sc->sc_codecctl2;
609 1.3.2.2 he l = (15 - ((vol & 0x3c0) >> 6)) * 16;
610 1.3.2.2 he r = (15 - (vol & 0x0f)) * 16;
611 1.3.2.2 he mc->un.mask = 1 << 1;
612 1.3.2.2 he mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
613 1.3.2.2 he mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
614 1.3.2.2 he return 0;
615 1.3.2.2 he
616 1.3.2.2 he default:
617 1.3.2.2 he return ENXIO;
618 1.3.2.2 he }
619 1.3.2.2 he
620 1.3.2.2 he return 0;
621 1.3.2.2 he }
622 1.3.2.2 he
623 1.3.2.2 he int
624 1.3.2.2 he awacs_query_devinfo(h, dip)
625 1.3.2.2 he void *h;
626 1.3.2.2 he mixer_devinfo_t *dip;
627 1.3.2.2 he {
628 1.3.2.2 he
629 1.3.2.2 he DPRINTF("query_devinfo %d\n", dip->index);
630 1.3.2.2 he
631 1.3.2.2 he switch (dip->index) {
632 1.3.2.2 he
633 1.3.2.2 he case AWACS_OUTPUT_SELECT:
634 1.3.2.2 he dip->mixer_class = AWACS_MONITOR_CLASS;
635 1.3.2.2 he strcpy(dip->label.name, AudioNoutput);
636 1.3.2.2 he dip->type = AUDIO_MIXER_SET;
637 1.3.2.2 he dip->prev = dip->next = AUDIO_MIXER_LAST;
638 1.3.2.2 he dip->un.s.num_mem = 2;
639 1.3.2.2 he strcpy(dip->un.s.member[0].label.name, AudioNspeaker);
640 1.3.2.2 he dip->un.s.member[0].mask = 1 << 0;
641 1.3.2.2 he strcpy(dip->un.s.member[1].label.name, AudioNheadphone);
642 1.3.2.2 he dip->un.s.member[1].mask = 1 << 1;
643 1.3.2.2 he return 0;
644 1.3.2.2 he
645 1.3.2.2 he case AWACS_VOL_SPEAKER:
646 1.3.2.2 he dip->mixer_class = AWACS_OUTPUT_CLASS;
647 1.3.2.2 he strcpy(dip->label.name, AudioNspeaker);
648 1.3.2.2 he dip->type = AUDIO_MIXER_VALUE;
649 1.3.2.2 he dip->prev = dip->next = AUDIO_MIXER_LAST;
650 1.3.2.2 he dip->un.v.num_channels = 2;
651 1.3.2.2 he strcpy(dip->un.v.units.name, AudioNvolume);
652 1.3.2.2 he return 0;
653 1.3.2.2 he
654 1.3.2.2 he case AWACS_VOL_HEADPHONE:
655 1.3.2.2 he dip->mixer_class = AWACS_OUTPUT_CLASS;
656 1.3.2.2 he strcpy(dip->label.name, AudioNheadphone);
657 1.3.2.2 he dip->type = AUDIO_MIXER_VALUE;
658 1.3.2.2 he dip->prev = dip->next = AUDIO_MIXER_LAST;
659 1.3.2.2 he dip->un.v.num_channels = 2;
660 1.3.2.2 he strcpy(dip->un.v.units.name, AudioNvolume);
661 1.3.2.2 he return 0;
662 1.3.2.2 he
663 1.3.2.2 he case AWACS_MONITOR_CLASS:
664 1.3.2.2 he dip->mixer_class = AWACS_MONITOR_CLASS;
665 1.3.2.2 he strcpy(dip->label.name, AudioCmonitor);
666 1.3.2.2 he dip->type = AUDIO_MIXER_CLASS;
667 1.3.2.2 he dip->next = dip->prev = AUDIO_MIXER_LAST;
668 1.3.2.2 he return 0;
669 1.3.2.2 he
670 1.3.2.2 he case AWACS_OUTPUT_CLASS:
671 1.3.2.2 he dip->mixer_class = AWACS_OUTPUT_CLASS;
672 1.3.2.2 he strcpy(dip->label.name, AudioCoutputs);
673 1.3.2.2 he dip->type = AUDIO_MIXER_CLASS;
674 1.3.2.2 he dip->next = dip->prev = AUDIO_MIXER_LAST;
675 1.3.2.2 he return 0;
676 1.3.2.2 he }
677 1.3.2.2 he
678 1.3.2.2 he return ENXIO;
679 1.3.2.2 he }
680 1.3.2.2 he
681 1.3.2.2 he size_t
682 1.3.2.2 he awacs_round_buffersize(h, dir, size)
683 1.3.2.2 he void *h;
684 1.3.2.2 he int dir;
685 1.3.2.2 he size_t size;
686 1.3.2.2 he {
687 1.3.2.2 he if (size > 65536)
688 1.3.2.2 he size = 65536;
689 1.3.2.2 he return size;
690 1.3.2.2 he }
691 1.3.2.2 he
692 1.3.2.2 he paddr_t
693 1.3.2.2 he awacs_mappage(h, mem, off, prot)
694 1.3.2.2 he void *h;
695 1.3.2.2 he void *mem;
696 1.3.2.2 he off_t off;
697 1.3.2.2 he int prot;
698 1.3.2.2 he {
699 1.3.2.2 he if (off < 0)
700 1.3.2.2 he return -1;
701 1.3.2.2 he return -1; /* XXX */
702 1.3.2.2 he }
703 1.3.2.2 he
704 1.3.2.2 he int
705 1.3.2.2 he awacs_get_props(h)
706 1.3.2.2 he void *h;
707 1.3.2.2 he {
708 1.3.2.2 he return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */;
709 1.3.2.2 he }
710 1.3.2.2 he
711 1.3.2.2 he int
712 1.3.2.2 he awacs_trigger_output(h, start, end, bsize, intr, arg, param)
713 1.3.2.2 he void *h;
714 1.3.2.2 he void *start, *end;
715 1.3.2.2 he int bsize;
716 1.3.2.2 he void (*intr)(void *);
717 1.3.2.2 he void *arg;
718 1.3.2.2 he struct audio_params *param;
719 1.3.2.2 he {
720 1.3.2.2 he struct awacs_softc *sc = h;
721 1.3.2.2 he struct dbdma_command *cmd = sc->sc_odmacmd;
722 1.3.2.2 he vaddr_t va;
723 1.3.2.2 he int i, len, intmode;
724 1.3.2.2 he
725 1.3.2.2 he DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize);
726 1.3.2.2 he
727 1.3.2.2 he sc->sc_ointr = intr;
728 1.3.2.2 he sc->sc_oarg = arg;
729 1.3.2.2 he sc->sc_opages = ((char *)end - (char *)start) / NBPG;
730 1.3.2.2 he
731 1.3.2.2 he #ifdef DIAGNOSTIC
732 1.3.2.2 he if (sc->sc_opages > 16)
733 1.3.2.2 he panic("awacs_trigger_output");
734 1.3.2.2 he #endif
735 1.3.2.2 he
736 1.3.2.2 he va = (vaddr_t)start;
737 1.3.2.2 he len = 0;
738 1.3.2.2 he for (i = sc->sc_opages; i > 0; i--) {
739 1.3.2.2 he len += NBPG;
740 1.3.2.2 he if (len < bsize)
741 1.3.2.2 he intmode = DBDMA_INT_NEVER;
742 1.3.2.2 he else {
743 1.3.2.2 he len = 0;
744 1.3.2.2 he intmode = DBDMA_INT_ALWAYS;
745 1.3.2.2 he }
746 1.3.2.2 he
747 1.3.2.2 he DBDMA_BUILD(cmd, DBDMA_CMD_OUT_MORE, 0, NBPG, vtophys(va),
748 1.3.2.2 he intmode, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
749 1.3.2.2 he va += NBPG;
750 1.3.2.2 he cmd++;
751 1.3.2.2 he }
752 1.3.2.2 he
753 1.3.2.2 he DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
754 1.3.2.2 he DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
755 1.3.2.2 he dbdma_st32(&cmd->d_cmddep, vtophys((vaddr_t)sc->sc_odmacmd));
756 1.3.2.2 he
757 1.3.2.2 he dbdma_start(sc->sc_odma, sc->sc_odmacmd);
758 1.3.2.2 he
759 1.3.2.2 he return 0;
760 1.3.2.2 he }
761 1.3.2.2 he
762 1.3.2.2 he int
763 1.3.2.2 he awacs_trigger_input(h, start, end, bsize, intr, arg, param)
764 1.3.2.2 he void *h;
765 1.3.2.2 he void *start, *end;
766 1.3.2.2 he int bsize;
767 1.3.2.2 he void (*intr)(void *);
768 1.3.2.2 he void *arg;
769 1.3.2.2 he struct audio_params *param;
770 1.3.2.2 he {
771 1.3.2.2 he printf("awacs_trigger_input called\n");
772 1.3.2.2 he
773 1.3.2.2 he return 1;
774 1.3.2.2 he }
775 1.3.2.2 he
776 1.3.2.2 he void
777 1.3.2.2 he awacs_set_speaker_volume(sc, left, right)
778 1.3.2.2 he struct awacs_softc *sc;
779 1.3.2.2 he int left, right;
780 1.3.2.2 he {
781 1.3.2.2 he int lval = 15 - (left & 0xff) / 16;
782 1.3.2.2 he int rval = 15 - (right & 0xff) / 16;
783 1.3.2.2 he
784 1.3.2.2 he DPRINTF("speaker_volume %d %d\n", lval, rval);
785 1.3.2.2 he
786 1.3.2.2 he sc->sc_codecctl4 &= ~0x3cf;
787 1.3.2.2 he sc->sc_codecctl4 |= (lval << 6) | rval;
788 1.3.2.2 he awacs_write_codec(sc, sc->sc_codecctl4);
789 1.3.2.2 he }
790 1.3.2.2 he
791 1.3.2.2 he void
792 1.3.2.2 he awacs_set_ext_volume(sc, left, right)
793 1.3.2.2 he struct awacs_softc *sc;
794 1.3.2.2 he int left, right;
795 1.3.2.2 he {
796 1.3.2.2 he int lval = 15 - (left & 0xff) / 16;
797 1.3.2.2 he int rval = 15 - (right & 0xff) / 16;
798 1.3.2.2 he
799 1.3.2.2 he DPRINTF("ext_volume %d %d\n", lval, rval);
800 1.3.2.2 he
801 1.3.2.2 he sc->sc_codecctl2 &= ~0x3cf;
802 1.3.2.2 he sc->sc_codecctl2 |= (lval << 6) | rval;
803 1.3.2.2 he awacs_write_codec(sc, sc->sc_codecctl2);
804 1.3.2.2 he }
805 1.3.2.2 he
806 1.3.2.2 he int
807 1.3.2.2 he awacs_set_rate(sc, rate)
808 1.3.2.2 he struct awacs_softc *sc;
809 1.3.2.2 he int rate;
810 1.3.2.2 he {
811 1.3.2.2 he int c;
812 1.3.2.2 he
813 1.3.2.2 he switch (rate) {
814 1.3.2.2 he
815 1.3.2.2 he case 44100:
816 1.3.2.2 he c = AWACS_RATE_44100;
817 1.3.2.2 he break;
818 1.3.2.2 he case 29400:
819 1.3.2.2 he c = AWACS_RATE_29400;
820 1.3.2.2 he break;
821 1.3.2.2 he case 22050:
822 1.3.2.2 he c = AWACS_RATE_22050;
823 1.3.2.2 he break;
824 1.3.2.2 he case 17640:
825 1.3.2.2 he c = AWACS_RATE_17640;
826 1.3.2.2 he break;
827 1.3.2.2 he case 14700:
828 1.3.2.2 he c = AWACS_RATE_14700;
829 1.3.2.2 he break;
830 1.3.2.2 he case 11025:
831 1.3.2.2 he c = AWACS_RATE_11025;
832 1.3.2.2 he break;
833 1.3.2.2 he case 8820:
834 1.3.2.2 he c = AWACS_RATE_8820;
835 1.3.2.2 he break;
836 1.3.2.2 he case 7350:
837 1.3.2.2 he c = AWACS_RATE_7350;
838 1.3.2.2 he break;
839 1.3.2.2 he default:
840 1.3.2.2 he return -1;
841 1.3.2.2 he }
842 1.3.2.2 he
843 1.3.2.2 he sc->sc_soundctl &= ~AWACS_RATE_MASK;
844 1.3.2.2 he sc->sc_soundctl |= c;
845 1.3.2.2 he awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
846 1.3.2.2 he
847 1.3.2.2 he return 0;
848 1.3.2.2 he }
849