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