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