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