am7930.c revision 1.33 1 1.33 christos /* $NetBSD: am7930.c,v 1.33 1997/10/19 20:34:54 christos Exp $ */
2 1.3 cgd
3 1.1 pk /*
4 1.1 pk * Copyright (c) 1995 Rolf Grossmann
5 1.1 pk * All rights reserved.
6 1.1 pk *
7 1.1 pk * Redistribution and use in source and binary forms, with or without
8 1.1 pk * modification, are permitted provided that the following conditions
9 1.1 pk * are met:
10 1.1 pk * 1. Redistributions of source code must retain the above copyright
11 1.1 pk * notice, this list of conditions and the following disclaimer.
12 1.1 pk * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 pk * notice, this list of conditions and the following disclaimer in the
14 1.1 pk * documentation and/or other materials provided with the distribution.
15 1.1 pk * 3. All advertising materials mentioning features or use of this software
16 1.1 pk * must display the following acknowledgement:
17 1.1 pk * This product includes software developed by Rolf Grossmann.
18 1.1 pk * 4. The name of the author may not be used to endorse or promote products
19 1.1 pk * derived from this software without specific prior written permission
20 1.1 pk *
21 1.1 pk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 1.1 pk * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 1.1 pk * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 1.1 pk * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 1.1 pk * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 1.1 pk * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 1.1 pk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 1.1 pk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 1.1 pk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 1.1 pk * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 1.1 pk */
32 1.1 pk
33 1.1 pk #include "audio.h"
34 1.1 pk #if NAUDIO > 0
35 1.1 pk
36 1.1 pk #include <sys/param.h>
37 1.1 pk #include <sys/systm.h>
38 1.1 pk #include <sys/errno.h>
39 1.1 pk #include <sys/ioctl.h>
40 1.1 pk #include <sys/device.h>
41 1.1 pk #include <sys/proc.h>
42 1.1 pk
43 1.1 pk #include <machine/autoconf.h>
44 1.1 pk #include <machine/cpu.h>
45 1.1 pk
46 1.1 pk #include <sys/audioio.h>
47 1.1 pk #include <dev/audio_if.h>
48 1.1 pk
49 1.3 cgd #include <dev/ic/am7930reg.h>
50 1.1 pk #include <sparc/dev/amd7930var.h>
51 1.1 pk
52 1.30 augustss #define AUDIO_ROM_NAME "audio"
53 1.30 augustss
54 1.4 brezak #ifdef AUDIO_DEBUG
55 1.1 pk extern void Dprintf __P((const char *, ...));
56 1.1 pk
57 1.1 pk int amd7930debug = 0;
58 1.1 pk #define DPRINTF(x) if (amd7930debug) Dprintf x
59 1.1 pk #else
60 1.1 pk #define DPRINTF(x)
61 1.1 pk #endif
62 1.1 pk
63 1.1 pk /*
64 1.1 pk * Software state, per AMD79C30 audio chip.
65 1.1 pk */
66 1.1 pk struct amd7930_softc {
67 1.1 pk struct device sc_dev; /* base device */
68 1.1 pk struct intrhand sc_hwih; /* hardware interrupt vector */
69 1.1 pk struct intrhand sc_swih; /* software interrupt vector */
70 1.1 pk
71 1.1 pk int sc_open; /* single use device */
72 1.1 pk int sc_locked; /* true when transfering data */
73 1.1 pk struct mapreg sc_map; /* current contents of map registers */
74 1.10 pk
75 1.1 pk u_char sc_rlevel; /* record level */
76 1.1 pk u_char sc_plevel; /* play level */
77 1.1 pk u_char sc_mlevel; /* monitor level */
78 1.1 pk u_char sc_out_port; /* output port */
79 1.1 pk
80 1.1 pk /* interfacing with the interrupt handlers */
81 1.1 pk void (*sc_rintr)(void*); /* input completion intr handler */
82 1.1 pk void *sc_rarg; /* arg for sc_rintr() */
83 1.1 pk void (*sc_pintr)(void*); /* output completion intr handler */
84 1.1 pk void *sc_parg; /* arg for sc_pintr() */
85 1.1 pk
86 1.1 pk /* sc_au is special in that the hardware interrupt handler uses it */
87 1.1 pk struct auio sc_au; /* recv and xmit buffers, etc */
88 1.2 pk #define sc_intrcnt sc_au.au_intrcnt /* statistics */
89 1.1 pk };
90 1.1 pk
91 1.1 pk /* interrupt interfaces */
92 1.1 pk #ifdef AUDIO_C_HANDLER
93 1.1 pk int amd7930hwintr __P((void *));
94 1.14 pk #if defined(SUN4M)
95 1.14 pk #define AUDIO_SET_SWINTR do { \
96 1.14 pk if (CPU_ISSUN4M) \
97 1.14 pk raise(0, 4); \
98 1.14 pk else \
99 1.14 pk ienab_bis(IE_L4); \
100 1.14 pk } while(0);
101 1.14 pk #else
102 1.1 pk #define AUDIO_SET_SWINTR ienab_bis(IE_L4)
103 1.14 pk #endif /* defined(SUN4M) */
104 1.1 pk #else
105 1.1 pk struct auio *auiop;
106 1.14 pk #endif /* AUDIO_C_HANDLER */
107 1.1 pk int amd7930swintr __P((void *));
108 1.1 pk
109 1.1 pk /* forward declarations */
110 1.1 pk void audio_setmap __P((volatile struct amd7930 *, struct mapreg *));
111 1.1 pk static void init_amd __P((volatile struct amd7930 *));
112 1.1 pk
113 1.1 pk /* autoconfiguration driver */
114 1.6 pk void amd7930attach __P((struct device *, struct device *, void *));
115 1.15 pk int amd7930match __P((struct device *, struct cfdata *, void *));
116 1.1 pk
117 1.27 augustss struct cfattach audioamd_ca = {
118 1.9 thorpej sizeof(struct amd7930_softc), amd7930match, amd7930attach
119 1.9 thorpej };
120 1.9 thorpej
121 1.27 augustss struct cfdriver audioamd_cd = {
122 1.27 augustss NULL, "audioamd", DV_DULL
123 1.1 pk };
124 1.1 pk
125 1.1 pk struct audio_device amd7930_device = {
126 1.1 pk "amd7930",
127 1.1 pk "x",
128 1.27 augustss "audioamd"
129 1.1 pk };
130 1.1 pk
131 1.1 pk /* Write 16 bits of data from variable v to the data port of the audio chip */
132 1.1 pk #define WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8)
133 1.1 pk
134 1.1 pk /* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */
135 1.1 pk
136 1.1 pk /*
137 1.1 pk * gx, gr & stg gains. this table must contain 256 elements with
138 1.1 pk * the 0th being "infinity" (the magic value 9008). The remaining
139 1.1 pk * elements match sun's gain curve (but with higher resolution):
140 1.1 pk * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
141 1.1 pk */
142 1.1 pk static const u_short gx_coeff[256] = {
143 1.21 pk 0x9008, 0x8e7c, 0x8e51, 0x8e45, 0x8d42, 0x8d3b, 0x8c36, 0x8c33,
144 1.1 pk 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
145 1.1 pk 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
146 1.1 pk 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
147 1.1 pk 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
148 1.1 pk 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
149 1.1 pk 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
150 1.1 pk 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
151 1.1 pk 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
152 1.1 pk 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
153 1.1 pk 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
154 1.1 pk 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
155 1.1 pk 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
156 1.1 pk 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
157 1.1 pk 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
158 1.1 pk 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
159 1.1 pk 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
160 1.1 pk 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
161 1.1 pk 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
162 1.1 pk 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
163 1.1 pk 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
164 1.1 pk 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
165 1.1 pk 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
166 1.1 pk 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
167 1.1 pk 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
168 1.1 pk 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
169 1.1 pk 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
170 1.1 pk 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
171 1.1 pk 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
172 1.1 pk 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
173 1.1 pk 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
174 1.1 pk 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
175 1.1 pk };
176 1.1 pk
177 1.1 pk /*
178 1.1 pk * second stage play gain.
179 1.1 pk */
180 1.1 pk static const u_short ger_coeff[] = {
181 1.1 pk 0x431f, /* 5. dB */
182 1.1 pk 0x331f, /* 5.5 dB */
183 1.1 pk 0x40dd, /* 6. dB */
184 1.1 pk 0x11dd, /* 6.5 dB */
185 1.1 pk 0x440f, /* 7. dB */
186 1.1 pk 0x411f, /* 7.5 dB */
187 1.1 pk 0x311f, /* 8. dB */
188 1.1 pk 0x5520, /* 8.5 dB */
189 1.1 pk 0x10dd, /* 9. dB */
190 1.1 pk 0x4211, /* 9.5 dB */
191 1.1 pk 0x410f, /* 10. dB */
192 1.1 pk 0x111f, /* 10.5 dB */
193 1.1 pk 0x600b, /* 11. dB */
194 1.1 pk 0x00dd, /* 11.5 dB */
195 1.1 pk 0x4210, /* 12. dB */
196 1.1 pk 0x110f, /* 13. dB */
197 1.1 pk 0x7200, /* 14. dB */
198 1.1 pk 0x2110, /* 15. dB */
199 1.1 pk 0x2200, /* 15.9 dB */
200 1.1 pk 0x000b, /* 16.9 dB */
201 1.1 pk 0x000f /* 18. dB */
202 1.1 pk #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
203 1.1 pk };
204 1.1 pk
205 1.1 pk /*
206 1.1 pk * Define our interface to the higher level audio driver.
207 1.1 pk */
208 1.26 augustss int amd7930_open __P((void *, int));
209 1.1 pk void amd7930_close __P((void *));
210 1.1 pk int amd7930_query_encoding __P((void *, struct audio_encoding *));
211 1.29 augustss int amd7930_set_params __P((void *, int, int, struct audio_params *, struct audio_params *));
212 1.1 pk int amd7930_round_blocksize __P((void *, int));
213 1.1 pk int amd7930_commit_settings __P((void *));
214 1.8 christos int amd7930_start_output __P((void *, void *, int, void (*)(void *),
215 1.8 christos void *));
216 1.8 christos int amd7930_start_input __P((void *, void *, int, void (*)(void *),
217 1.8 christos void *));
218 1.1 pk int amd7930_halt_output __P((void *));
219 1.1 pk int amd7930_halt_input __P((void *));
220 1.1 pk int amd7930_getdev __P((void *, struct audio_device *));
221 1.1 pk int amd7930_set_port __P((void *, mixer_ctrl_t *));
222 1.1 pk int amd7930_get_port __P((void *, mixer_ctrl_t *));
223 1.1 pk int amd7930_query_devinfo __P((void *, mixer_devinfo_t *));
224 1.26 augustss int amd7930_get_props __P((void *));
225 1.1 pk
226 1.1 pk
227 1.1 pk struct audio_hw_if sa_hw_if = {
228 1.1 pk amd7930_open,
229 1.1 pk amd7930_close,
230 1.24 augustss 0,
231 1.1 pk amd7930_query_encoding,
232 1.18 augustss amd7930_set_params,
233 1.1 pk amd7930_round_blocksize,
234 1.1 pk amd7930_commit_settings,
235 1.24 augustss 0,
236 1.24 augustss 0,
237 1.1 pk amd7930_start_output,
238 1.1 pk amd7930_start_input,
239 1.1 pk amd7930_halt_output,
240 1.1 pk amd7930_halt_input,
241 1.24 augustss 0,
242 1.1 pk amd7930_getdev,
243 1.24 augustss 0,
244 1.1 pk amd7930_set_port,
245 1.1 pk amd7930_get_port,
246 1.1 pk amd7930_query_devinfo,
247 1.23 augustss 0,
248 1.23 augustss 0,
249 1.23 augustss 0,
250 1.25 augustss 0,
251 1.26 augustss amd7930_get_props,
252 1.1 pk };
253 1.1 pk
254 1.1 pk /* autoconfig routines */
255 1.1 pk
256 1.1 pk int
257 1.15 pk amd7930match(parent, cf, aux)
258 1.1 pk struct device *parent;
259 1.15 pk struct cfdata *cf;
260 1.15 pk void *aux;
261 1.1 pk {
262 1.1 pk register struct confargs *ca = aux;
263 1.1 pk register struct romaux *ra = &ca->ca_ra;
264 1.1 pk
265 1.7 pk if (CPU_ISSUN4)
266 1.1 pk return (0);
267 1.30 augustss return (strcmp(AUDIO_ROM_NAME, ra->ra_name) == 0);
268 1.1 pk }
269 1.1 pk
270 1.1 pk /*
271 1.1 pk * Audio chip found.
272 1.1 pk */
273 1.1 pk void
274 1.6 pk amd7930attach(parent, self, args)
275 1.1 pk struct device *parent, *self;
276 1.1 pk void *args;
277 1.1 pk {
278 1.1 pk register struct amd7930_softc *sc = (struct amd7930_softc *)self;
279 1.1 pk register struct confargs *ca = args;
280 1.1 pk register struct romaux *ra = &ca->ca_ra;
281 1.1 pk register volatile struct amd7930 *amd;
282 1.1 pk register int pri;
283 1.1 pk
284 1.1 pk if (ra->ra_nintr != 1) {
285 1.13 christos printf(": expected 1 interrupt, got %d\n", ra->ra_nintr);
286 1.1 pk return;
287 1.1 pk }
288 1.1 pk pri = ra->ra_intr[0].int_pri;
289 1.13 christos printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT);
290 1.1 pk amd = (volatile struct amd7930 *)(ra->ra_vaddr ?
291 1.22 pk ra->ra_vaddr : mapiodev(ra->ra_reg, 0, sizeof (*amd)));
292 1.1 pk
293 1.1 pk sc->sc_map.mr_mmr1 = AMD_MMR1_GX | AMD_MMR1_GER |
294 1.1 pk AMD_MMR1_GR | AMD_MMR1_STG;
295 1.1 pk sc->sc_au.au_amd = amd;
296 1.1 pk /* set boot defaults */
297 1.1 pk sc->sc_rlevel = 128;
298 1.1 pk sc->sc_plevel = 128;
299 1.1 pk sc->sc_mlevel = 0;
300 1.1 pk sc->sc_out_port = SUNAUDIO_SPEAKER;
301 1.10 pk
302 1.1 pk init_amd(amd);
303 1.1 pk
304 1.1 pk #ifndef AUDIO_C_HANDLER
305 1.1 pk auiop = &sc->sc_au;
306 1.1 pk intr_fasttrap(pri, amd7930_trap);
307 1.1 pk #else
308 1.1 pk sc->sc_hwih.ih_fun = amd7930hwintr;
309 1.1 pk sc->sc_hwih.ih_arg = &sc->sc_au;
310 1.1 pk intr_establish(pri, &sc->sc_hwih);
311 1.1 pk #endif
312 1.1 pk sc->sc_swih.ih_fun = amd7930swintr;
313 1.1 pk sc->sc_swih.ih_arg = sc;
314 1.1 pk intr_establish(PIL_AUSOFT, &sc->sc_swih);
315 1.2 pk
316 1.2 pk evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
317 1.1 pk
318 1.27 augustss audio_attach_mi(&sa_hw_if, 0, sc, &sc->sc_dev);
319 1.1 pk }
320 1.1 pk
321 1.1 pk static void
322 1.1 pk init_amd(amd)
323 1.1 pk register volatile struct amd7930 *amd;
324 1.1 pk {
325 1.1 pk /* disable interrupts */
326 1.1 pk amd->cr = AMDR_INIT;
327 1.1 pk amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
328 1.1 pk
329 1.1 pk /*
330 1.1 pk * Initialize the mux unit. We use MCR3 to route audio (MAP)
331 1.1 pk * through channel Bb. MCR1 and MCR2 are unused.
332 1.1 pk * Setting the INT enable bit in MCR4 will generate an interrupt
333 1.1 pk * on each converted audio sample.
334 1.1 pk */
335 1.1 pk amd->cr = AMDR_MUX_1_4;
336 1.1 pk amd->dr = 0;
337 1.1 pk amd->dr = 0;
338 1.1 pk amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA;
339 1.1 pk amd->dr = AMD_MCR4_INT_ENABLE;
340 1.1 pk }
341 1.1 pk
342 1.1 pk int
343 1.26 augustss amd7930_open(addr, flags)
344 1.26 augustss void *addr;
345 1.1 pk int flags;
346 1.1 pk {
347 1.26 augustss struct amd7930_softc *sc = addr;
348 1.1 pk
349 1.26 augustss DPRINTF(("sa_open: unit %p\n", sc));
350 1.1 pk
351 1.1 pk if (sc->sc_open)
352 1.1 pk return (EBUSY);
353 1.1 pk sc->sc_open = 1;
354 1.1 pk sc->sc_locked = 0;
355 1.1 pk sc->sc_rintr = 0;
356 1.1 pk sc->sc_rarg = 0;
357 1.1 pk sc->sc_pintr = 0;
358 1.1 pk sc->sc_parg = 0;
359 1.1 pk
360 1.1 pk sc->sc_au.au_rdata = 0;
361 1.1 pk sc->sc_au.au_pdata = 0;
362 1.1 pk
363 1.1 pk DPRINTF(("saopen: ok -> sc=0x%x\n",sc));
364 1.1 pk
365 1.1 pk return (0);
366 1.1 pk }
367 1.1 pk
368 1.1 pk void
369 1.1 pk amd7930_close(addr)
370 1.1 pk void *addr;
371 1.1 pk {
372 1.1 pk register struct amd7930_softc *sc = addr;
373 1.1 pk
374 1.1 pk DPRINTF(("sa_close: sc=0x%x\n", sc));
375 1.1 pk /*
376 1.1 pk * halt i/o, clear open flag, and done.
377 1.1 pk */
378 1.1 pk amd7930_halt_input(sc);
379 1.1 pk amd7930_halt_output(sc);
380 1.1 pk sc->sc_open = 0;
381 1.1 pk
382 1.1 pk DPRINTF(("sa_close: closed.\n"));
383 1.1 pk }
384 1.1 pk
385 1.1 pk int
386 1.28 augustss amd7930_set_params(addr, setmode, usemode, p, r)
387 1.1 pk void *addr;
388 1.28 augustss int setmode, usemode;
389 1.28 augustss struct audio_params *p, *r;
390 1.1 pk {
391 1.18 augustss if (p->sample_rate < 7500 || p->sample_rate > 8500 ||
392 1.18 augustss p->encoding != AUDIO_ENCODING_ULAW ||
393 1.18 augustss p->precision != 8 ||
394 1.18 augustss p->channels != 1)
395 1.1 pk return EINVAL;
396 1.20 augustss p->sample_rate = 8000; /* no other sampling rates supported by amd chip */
397 1.20 augustss
398 1.20 augustss return 0;
399 1.1 pk }
400 1.1 pk
401 1.1 pk int
402 1.1 pk amd7930_query_encoding(addr, fp)
403 1.1 pk void *addr;
404 1.1 pk struct audio_encoding *fp;
405 1.1 pk {
406 1.1 pk switch (fp->index) { /* ??? */
407 1.1 pk case 0:
408 1.19 augustss strcpy(fp->name, AudioEmulaw);
409 1.19 augustss fp->encoding = AUDIO_ENCODING_ULAW;
410 1.19 augustss fp->precision = 8;
411 1.19 augustss fp->flags = 0;
412 1.1 pk break;
413 1.1 pk default:
414 1.1 pk return(EINVAL);
415 1.1 pk /*NOTREACHED*/
416 1.1 pk }
417 1.1 pk return(0);
418 1.1 pk }
419 1.1 pk
420 1.1 pk int
421 1.1 pk amd7930_round_blocksize(addr, blk)
422 1.1 pk void *addr;
423 1.1 pk int blk;
424 1.1 pk {
425 1.1 pk return(blk);
426 1.1 pk }
427 1.1 pk
428 1.1 pk int
429 1.1 pk amd7930_commit_settings(addr)
430 1.1 pk void *addr;
431 1.1 pk {
432 1.1 pk register struct amd7930_softc *sc = addr;
433 1.1 pk register struct mapreg *map;
434 1.1 pk register volatile struct amd7930 *amd;
435 1.1 pk register int s, level;
436 1.10 pk
437 1.1 pk DPRINTF(("sa_commit.\n"));
438 1.1 pk
439 1.1 pk map = &sc->sc_map;
440 1.1 pk amd = sc->sc_au.au_amd;
441 1.1 pk
442 1.1 pk map->mr_gx = gx_coeff[sc->sc_rlevel];
443 1.1 pk map->mr_stgr = gx_coeff[sc->sc_mlevel];
444 1.10 pk
445 1.1 pk level = (sc->sc_plevel * (256 + NGER)) >> 8;
446 1.1 pk if (level >= 256) {
447 1.1 pk map->mr_ger = ger_coeff[level - 256];
448 1.1 pk map->mr_gr = gx_coeff[255];
449 1.1 pk } else {
450 1.1 pk map->mr_ger = ger_coeff[0];
451 1.1 pk map->mr_gr = gx_coeff[level];
452 1.1 pk }
453 1.1 pk
454 1.1 pk if (sc->sc_out_port == SUNAUDIO_SPEAKER)
455 1.1 pk map->mr_mmr2 |= AMD_MMR2_LS;
456 1.1 pk else
457 1.1 pk map->mr_mmr2 &= ~AMD_MMR2_LS;
458 1.10 pk
459 1.1 pk s = splaudio();
460 1.10 pk
461 1.1 pk amd->cr = AMDR_MAP_MMR1;
462 1.1 pk amd->dr = map->mr_mmr1;
463 1.1 pk amd->cr = AMDR_MAP_GX;
464 1.1 pk WAMD16(amd, map->mr_gx);
465 1.1 pk amd->cr = AMDR_MAP_STG;
466 1.1 pk WAMD16(amd, map->mr_stgr);
467 1.1 pk amd->cr = AMDR_MAP_GR;
468 1.1 pk WAMD16(amd, map->mr_gr);
469 1.1 pk amd->cr = AMDR_MAP_GER;
470 1.1 pk WAMD16(amd, map->mr_ger);
471 1.1 pk amd->cr = AMDR_MAP_MMR2;
472 1.1 pk amd->dr = map->mr_mmr2;
473 1.1 pk
474 1.1 pk splx(s);
475 1.1 pk return(0);
476 1.1 pk }
477 1.1 pk
478 1.1 pk int
479 1.1 pk amd7930_start_output(addr, p, cc, intr, arg)
480 1.1 pk void *addr;
481 1.1 pk void *p;
482 1.1 pk int cc;
483 1.8 christos void (*intr) __P((void *));
484 1.1 pk void *arg;
485 1.1 pk {
486 1.1 pk register struct amd7930_softc *sc = addr;
487 1.1 pk
488 1.4 brezak #ifdef AUDIO_DEBUG
489 1.1 pk if (amd7930debug > 1)
490 1.1 pk Dprintf("sa_start_output: cc=%d 0x%x (0x%x)\n", cc, intr, arg);
491 1.1 pk #endif
492 1.1 pk
493 1.1 pk if (!sc->sc_locked) {
494 1.1 pk register volatile struct amd7930 *amd;
495 1.1 pk
496 1.1 pk amd = sc->sc_au.au_amd;
497 1.1 pk amd->cr = AMDR_INIT;
498 1.1 pk amd->dr = AMD_INIT_PMS_ACTIVE;
499 1.1 pk sc->sc_locked = 1;
500 1.1 pk DPRINTF(("sa_start_output: started intrs.\n"));
501 1.1 pk }
502 1.1 pk sc->sc_pintr = intr;
503 1.1 pk sc->sc_parg = arg;
504 1.1 pk sc->sc_au.au_pdata = p;
505 1.1 pk sc->sc_au.au_pend = p + cc - 1;
506 1.1 pk return(0);
507 1.1 pk }
508 1.1 pk
509 1.1 pk /* ARGSUSED */
510 1.1 pk int
511 1.1 pk amd7930_start_input(addr, p, cc, intr, arg)
512 1.1 pk void *addr;
513 1.1 pk void *p;
514 1.1 pk int cc;
515 1.8 christos void (*intr) __P((void *));
516 1.1 pk void *arg;
517 1.1 pk {
518 1.1 pk register struct amd7930_softc *sc = addr;
519 1.1 pk
520 1.4 brezak #ifdef AUDIO_DEBUG
521 1.1 pk if (amd7930debug > 1)
522 1.1 pk Dprintf("sa_start_input: cc=%d 0x%x (0x%x)\n", cc, intr, arg);
523 1.1 pk #endif
524 1.1 pk
525 1.1 pk if (!sc->sc_locked) {
526 1.1 pk register volatile struct amd7930 *amd;
527 1.1 pk
528 1.1 pk amd = sc->sc_au.au_amd;
529 1.1 pk amd->cr = AMDR_INIT;
530 1.1 pk amd->dr = AMD_INIT_PMS_ACTIVE;
531 1.1 pk sc->sc_locked = 1;
532 1.1 pk DPRINTF(("sa_start_input: started intrs.\n"));
533 1.1 pk }
534 1.1 pk sc->sc_rintr = intr;
535 1.1 pk sc->sc_rarg = arg;
536 1.1 pk sc->sc_au.au_rdata = p;
537 1.1 pk sc->sc_au.au_rend = p + cc -1;
538 1.1 pk return(0);
539 1.1 pk }
540 1.1 pk
541 1.1 pk int
542 1.1 pk amd7930_halt_output(addr)
543 1.1 pk void *addr;
544 1.1 pk {
545 1.1 pk register struct amd7930_softc *sc = addr;
546 1.1 pk register volatile struct amd7930 *amd;
547 1.1 pk
548 1.1 pk /* XXX only halt, if input is also halted ?? */
549 1.1 pk amd = sc->sc_au.au_amd;
550 1.1 pk amd->cr = AMDR_INIT;
551 1.1 pk amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
552 1.1 pk sc->sc_locked = 0;
553 1.1 pk
554 1.1 pk return(0);
555 1.1 pk }
556 1.1 pk
557 1.1 pk int
558 1.1 pk amd7930_halt_input(addr)
559 1.1 pk void *addr;
560 1.1 pk {
561 1.1 pk register struct amd7930_softc *sc = addr;
562 1.1 pk register volatile struct amd7930 *amd;
563 1.1 pk
564 1.1 pk /* XXX only halt, if output is also halted ?? */
565 1.1 pk amd = sc->sc_au.au_amd;
566 1.1 pk amd->cr = AMDR_INIT;
567 1.1 pk amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
568 1.1 pk sc->sc_locked = 0;
569 1.1 pk
570 1.1 pk return(0);
571 1.1 pk }
572 1.1 pk
573 1.1 pk int
574 1.1 pk amd7930_getdev(addr, retp)
575 1.1 pk void *addr;
576 1.1 pk struct audio_device *retp;
577 1.1 pk {
578 1.1 pk *retp = amd7930_device;
579 1.1 pk return 0;
580 1.1 pk }
581 1.1 pk
582 1.1 pk int
583 1.1 pk amd7930_set_port(addr, cp)
584 1.1 pk void *addr;
585 1.1 pk mixer_ctrl_t *cp;
586 1.1 pk {
587 1.1 pk register struct amd7930_softc *sc = addr;
588 1.1 pk
589 1.1 pk DPRINTF(("amd7930_set_port: port=%d", cp->dev));
590 1.1 pk
591 1.1 pk if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1)
592 1.1 pk return(EINVAL);
593 1.10 pk
594 1.1 pk switch(cp->dev) {
595 1.1 pk case SUNAUDIO_MIC_PORT:
596 1.1 pk sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
597 1.1 pk break;
598 1.1 pk case SUNAUDIO_SPEAKER:
599 1.1 pk case SUNAUDIO_HEADPHONES:
600 1.1 pk sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
601 1.1 pk break;
602 1.1 pk case SUNAUDIO_MONITOR:
603 1.1 pk sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
604 1.1 pk break;
605 1.32 augustss case SUNAUDIO_SOURCE:
606 1.33 christos if (cp->un.ord != SUNAUDIO_MIC_PORT)
607 1.32 augustss return EINVAL;
608 1.32 augustss break;
609 1.32 augustss case SUNAUDIO_OUTPUT:
610 1.33 christos if (cp->un.ord != SUNAUDIO_SPEAKER &&
611 1.33 christos cp->un.ord != SUNAUDIO_HEADPHONES)
612 1.32 augustss return EINVAL;
613 1.33 christos sc->sc_out_port = cp->un.ord;
614 1.32 augustss break;
615 1.1 pk default:
616 1.1 pk return(EINVAL);
617 1.1 pk /* NOTREACHED */
618 1.1 pk }
619 1.1 pk return(0);
620 1.1 pk }
621 1.1 pk
622 1.1 pk int
623 1.1 pk amd7930_get_port(addr, cp)
624 1.1 pk void *addr;
625 1.1 pk mixer_ctrl_t *cp;
626 1.1 pk {
627 1.1 pk register struct amd7930_softc *sc = addr;
628 1.1 pk
629 1.1 pk DPRINTF(("amd7930_get_port: port=%d", cp->dev));
630 1.1 pk
631 1.1 pk if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1)
632 1.1 pk return(EINVAL);
633 1.10 pk
634 1.1 pk switch(cp->dev) {
635 1.1 pk case SUNAUDIO_MIC_PORT:
636 1.1 pk cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
637 1.1 pk break;
638 1.1 pk case SUNAUDIO_SPEAKER:
639 1.1 pk case SUNAUDIO_HEADPHONES:
640 1.1 pk cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
641 1.1 pk break;
642 1.1 pk case SUNAUDIO_MONITOR:
643 1.1 pk cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
644 1.1 pk break;
645 1.32 augustss case SUNAUDIO_SOURCE:
646 1.33 christos cp->un.ord = SUNAUDIO_MIC_PORT;
647 1.32 augustss break;
648 1.32 augustss case SUNAUDIO_OUTPUT:
649 1.33 christos cp->un.ord = sc->sc_out_port;
650 1.32 augustss break;
651 1.1 pk default:
652 1.1 pk return(EINVAL);
653 1.1 pk /* NOTREACHED */
654 1.1 pk }
655 1.1 pk return(0);
656 1.26 augustss }
657 1.26 augustss
658 1.26 augustss int
659 1.26 augustss amd7930_get_props(addr)
660 1.26 augustss void *addr;
661 1.26 augustss {
662 1.26 augustss return AUDIO_PROP_FULLDUPLEX;
663 1.1 pk }
664 1.1 pk
665 1.1 pk int
666 1.1 pk amd7930_query_devinfo(addr, dip)
667 1.1 pk void *addr;
668 1.1 pk register mixer_devinfo_t *dip;
669 1.1 pk {
670 1.1 pk switch(dip->index) {
671 1.1 pk case SUNAUDIO_MIC_PORT:
672 1.1 pk dip->type = AUDIO_MIXER_VALUE;
673 1.1 pk dip->mixer_class = SUNAUDIO_INPUT_CLASS;
674 1.1 pk dip->prev = dip->next = AUDIO_MIXER_LAST;
675 1.1 pk strcpy(dip->label.name, AudioNmicrophone);
676 1.1 pk dip->un.v.num_channels = 1;
677 1.1 pk strcpy(dip->un.v.units.name, AudioNvolume);
678 1.1 pk break;
679 1.1 pk case SUNAUDIO_SPEAKER:
680 1.1 pk dip->type = AUDIO_MIXER_VALUE;
681 1.1 pk dip->mixer_class = SUNAUDIO_OUTPUT_CLASS;
682 1.1 pk dip->prev = dip->next = AUDIO_MIXER_LAST;
683 1.1 pk strcpy(dip->label.name, AudioNspeaker);
684 1.1 pk dip->un.v.num_channels = 1;
685 1.1 pk strcpy(dip->un.v.units.name, AudioNvolume);
686 1.1 pk break;
687 1.1 pk case SUNAUDIO_HEADPHONES:
688 1.1 pk dip->type = AUDIO_MIXER_VALUE;
689 1.1 pk dip->mixer_class = SUNAUDIO_OUTPUT_CLASS;
690 1.1 pk dip->prev = dip->next = AUDIO_MIXER_LAST;
691 1.1 pk strcpy(dip->label.name, AudioNheadphone);
692 1.1 pk dip->un.v.num_channels = 1;
693 1.1 pk strcpy(dip->un.v.units.name, AudioNvolume);
694 1.1 pk break;
695 1.32 augustss case SUNAUDIO_SOURCE:
696 1.32 augustss dip->type = AUDIO_MIXER_ENUM;
697 1.32 augustss dip->mixer_class = SUNAUDIO_RECORD_CLASS;
698 1.32 augustss dip->next = dip->prev = AUDIO_MIXER_LAST;
699 1.32 augustss strcpy(dip->label.name, AudioNsource);
700 1.32 augustss dip->un.e.num_mem = 1;
701 1.32 augustss strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
702 1.32 augustss dip->un.e.member[0].ord = SUNAUDIO_MIC_PORT;
703 1.32 augustss break;
704 1.32 augustss case SUNAUDIO_OUTPUT:
705 1.32 augustss dip->type = AUDIO_MIXER_ENUM;
706 1.32 augustss dip->mixer_class = SUNAUDIO_MONITOR_CLASS;
707 1.32 augustss dip->next = dip->prev = AUDIO_MIXER_LAST;
708 1.32 augustss strcpy(dip->label.name, AudioNoutput);
709 1.32 augustss dip->un.e.num_mem = 2;
710 1.32 augustss strcpy(dip->un.e.member[0].label.name, AudioNspeaker);
711 1.32 augustss dip->un.e.member[0].ord = SUNAUDIO_SPEAKER;
712 1.32 augustss strcpy(dip->un.e.member[1].label.name, AudioNheadphone);
713 1.32 augustss dip->un.e.member[1].ord = SUNAUDIO_HEADPHONES;
714 1.32 augustss break;
715 1.1 pk case SUNAUDIO_INPUT_CLASS:
716 1.1 pk dip->type = AUDIO_MIXER_CLASS;
717 1.1 pk dip->mixer_class = SUNAUDIO_INPUT_CLASS;
718 1.1 pk dip->next = dip->prev = AUDIO_MIXER_LAST;
719 1.31 mycroft strcpy(dip->label.name, AudioCinputs);
720 1.1 pk break;
721 1.1 pk case SUNAUDIO_OUTPUT_CLASS:
722 1.1 pk dip->type = AUDIO_MIXER_CLASS;
723 1.1 pk dip->mixer_class = SUNAUDIO_OUTPUT_CLASS;
724 1.1 pk dip->next = dip->prev = AUDIO_MIXER_LAST;
725 1.32 augustss strcpy(dip->label.name, AudioCrecord);
726 1.32 augustss break;
727 1.32 augustss case SUNAUDIO_RECORD_CLASS:
728 1.32 augustss dip->type = AUDIO_MIXER_CLASS;
729 1.32 augustss dip->mixer_class = SUNAUDIO_RECORD_CLASS;
730 1.32 augustss dip->next = dip->prev = AUDIO_MIXER_LAST;
731 1.31 mycroft strcpy(dip->label.name, AudioCoutputs);
732 1.32 augustss break;
733 1.32 augustss case SUNAUDIO_MONITOR:
734 1.32 augustss dip->type = AUDIO_MIXER_CLASS;
735 1.32 augustss dip->mixer_class = SUNAUDIO_MONITOR_CLASS;
736 1.32 augustss dip->next = dip->prev = AUDIO_MIXER_LAST;
737 1.32 augustss strcpy(dip->label.name, AudioCmonitor);
738 1.1 pk break;
739 1.1 pk default:
740 1.1 pk return ENXIO;
741 1.1 pk /*NOTREACHED*/
742 1.1 pk }
743 1.1 pk
744 1.1 pk DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
745 1.10 pk
746 1.1 pk return(0);
747 1.1 pk }
748 1.1 pk
749 1.1 pk #ifdef AUDIO_C_HANDLER
750 1.1 pk int
751 1.1 pk amd7930hwintr(au0)
752 1.1 pk void *au0;
753 1.1 pk {
754 1.1 pk register struct auio *au = au0;
755 1.1 pk register volatile struct amd7930 *amd = au->au_amd;
756 1.1 pk register u_char *d, *e;
757 1.1 pk register int k;
758 1.1 pk
759 1.1 pk k = amd->ir; /* clear interrupt */
760 1.1 pk
761 1.1 pk /* receive incoming data */
762 1.1 pk d = au->au_rdata;
763 1.1 pk e = au->au_rend;
764 1.1 pk if (d && d <= e) {
765 1.1 pk *d = amd->bbrb;
766 1.1 pk au->au_rdata++;
767 1.1 pk if (d == e) {
768 1.4 brezak #ifdef AUDIO_DEBUG
769 1.1 pk if (amd7930debug > 1)
770 1.1 pk Dprintf("amd7930hwintr: swintr(r) requested");
771 1.1 pk #endif
772 1.1 pk AUDIO_SET_SWINTR;
773 1.1 pk }
774 1.1 pk }
775 1.1 pk
776 1.1 pk /* send outgoing data */
777 1.1 pk d = au->au_pdata;
778 1.1 pk e = au->au_pend;
779 1.1 pk if (d && d <= e) {
780 1.1 pk amd->bbtb = *d;
781 1.1 pk au->au_pdata++;
782 1.1 pk if (d == e) {
783 1.4 brezak #ifdef AUDIO_DEBUG
784 1.1 pk if (amd7930debug > 1)
785 1.1 pk Dprintf("amd7930hwintr: swintr(p) requested");
786 1.1 pk #endif
787 1.1 pk AUDIO_SET_SWINTR;
788 1.1 pk }
789 1.1 pk }
790 1.1 pk
791 1.11 mrg *(au->au_intrcnt)++;
792 1.1 pk return (1);
793 1.1 pk }
794 1.1 pk #endif /* AUDIO_C_HANDLER */
795 1.1 pk
796 1.1 pk int
797 1.1 pk amd7930swintr(sc0)
798 1.1 pk void *sc0;
799 1.1 pk {
800 1.1 pk register struct amd7930_softc *sc = sc0;
801 1.1 pk register struct auio *au;
802 1.1 pk register int s, ret = 0;
803 1.1 pk
804 1.4 brezak #ifdef AUDIO_DEBUG
805 1.1 pk if (amd7930debug > 1)
806 1.1 pk Dprintf("audiointr: sc=0x%x\n",sc);
807 1.1 pk #endif
808 1.1 pk
809 1.1 pk au = &sc->sc_au;
810 1.1 pk s = splaudio();
811 1.1 pk if (au->au_rdata > au->au_rend && sc->sc_rintr != NULL) {
812 1.1 pk splx(s);
813 1.1 pk ret = 1;
814 1.1 pk (*sc->sc_rintr)(sc->sc_rarg);
815 1.1 pk s = splaudio();
816 1.1 pk }
817 1.1 pk if (au->au_pdata > au->au_pend && sc->sc_pintr != NULL) {
818 1.1 pk splx(s);
819 1.1 pk ret = 1;
820 1.1 pk (*sc->sc_pintr)(sc->sc_parg);
821 1.1 pk } else
822 1.1 pk splx(s);
823 1.1 pk return (ret);
824 1.1 pk }
825 1.1 pk #endif /* NAUDIO > 0 */
826