xref: /netbsd-src/sys/dev/sbus/cs4231_sbus.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: cs4231_sbus.c,v 1.36 2007/12/03 15:34:33 ad Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998, 1999, 2002, 2007 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Paul Kranenburg.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: cs4231_sbus.c,v 1.36 2007/12/03 15:34:33 ad Exp $");
41 
42 #include "audio.h"
43 #if NAUDIO > 0
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/errno.h>
48 #include <sys/device.h>
49 #include <sys/malloc.h>
50 #include <sys/bus.h>
51 #include <sys/intr.h>
52 
53 #include <dev/sbus/sbusvar.h>
54 
55 #include <sys/audioio.h>
56 #include <dev/audio_if.h>
57 
58 #include <dev/ic/ad1848reg.h>
59 #include <dev/ic/cs4231reg.h>
60 #include <dev/ic/ad1848var.h>
61 #include <dev/ic/cs4231var.h>
62 
63 #include <dev/ic/apcdmareg.h>
64 
65 #ifdef AUDIO_DEBUG
66 int cs4231_sbus_debug = 0;
67 #define DPRINTF(x)      if (cs4231_sbus_debug) printf x
68 #else
69 #define DPRINTF(x)
70 #endif
71 
72 /* where APC DMA registers are located */
73 #define CS4231_APCDMA_OFFSET	16
74 
75 /* interrupt enable bits except those specific for playback/capture */
76 #define APC_ENABLE		(APC_EI | APC_IE | APC_EIE)
77 
78 struct cs4231_sbus_softc {
79 	struct cs4231_softc sc_cs4231;
80 
81 	void *sc_pint;
82 	void *sc_rint;
83 	struct sbusdev sc_sd;			/* sbus device */
84 	bus_space_tag_t sc_bt;			/* DMA controller tag */
85 	bus_space_handle_t sc_bh;		/* DMA controller registers */
86 };
87 
88 
89 static int	cs4231_sbus_match(struct device *, struct cfdata *, void *);
90 static void	cs4231_sbus_attach(struct device *, struct device *, void *);
91 static void	cs4231_sbus_pint(void *);
92 static void	cs4231_sbus_rint(void *);
93 
94 CFATTACH_DECL(audiocs_sbus, sizeof(struct cs4231_sbus_softc),
95     cs4231_sbus_match, cs4231_sbus_attach, NULL, NULL);
96 
97 /* audio_hw_if methods specific to apc DMA */
98 static int	cs4231_sbus_trigger_output(void *, void *, void *, int,
99 					   void (*)(void *), void *,
100 					   const audio_params_t *);
101 static int	cs4231_sbus_trigger_input(void *, void *, void *, int,
102 					  void (*)(void *), void *,
103 					  const audio_params_t *);
104 static int	cs4231_sbus_halt_output(void *);
105 static int	cs4231_sbus_halt_input(void *);
106 
107 const struct audio_hw_if audiocs_sbus_hw_if = {
108 	cs4231_open,
109 	cs4231_close,
110 	NULL,			/* drain */
111 	ad1848_query_encoding,
112 	ad1848_set_params,
113 	NULL,			/* round_blocksize */
114 	ad1848_commit_settings,
115 	NULL,			/* init_output */
116 	NULL,			/* init_input */
117 	NULL,			/* start_output */
118 	NULL,			/* start_input */
119 	cs4231_sbus_halt_output,
120 	cs4231_sbus_halt_input,
121 	NULL,			/* speaker_ctl */
122 	cs4231_getdev,
123 	NULL,			/* setfd */
124 	cs4231_set_port,
125 	cs4231_get_port,
126 	cs4231_query_devinfo,
127 	cs4231_malloc,
128 	cs4231_free,
129 	NULL,			/* round_buffersize */
130 	NULL,			/* mappage */
131 	cs4231_get_props,
132 	cs4231_sbus_trigger_output,
133 	cs4231_sbus_trigger_input,
134 	NULL,			/* dev_ioctl */
135 	NULL,			/* powerstate */
136 };
137 
138 
139 #ifdef AUDIO_DEBUG
140 static void	cs4231_sbus_regdump(char *, struct cs4231_sbus_softc *);
141 #endif
142 
143 static int	cs4231_sbus_intr(void *);
144 
145 
146 
147 static int
148 cs4231_sbus_match(struct device *parent, struct cfdata *cf, void *aux)
149 {
150 	struct sbus_attach_args *sa;
151 
152 	sa = aux;
153 	return strcmp(sa->sa_name, AUDIOCS_PROM_NAME) == 0;
154 }
155 
156 
157 static void
158 cs4231_sbus_attach(struct device *parent, struct device *self, void *aux)
159 {
160 	struct cs4231_sbus_softc *sbsc;
161 	struct cs4231_softc *sc;
162 	struct sbus_attach_args *sa;
163 	bus_space_handle_t bh;
164 
165 	sbsc = (struct cs4231_sbus_softc *)self;
166 	sc = &sbsc->sc_cs4231;
167 	sa = aux;
168 	sbsc->sc_bt = sc->sc_bustag = sa->sa_bustag;
169 	sc->sc_dmatag = sa->sa_dmatag;
170 
171 	sbsc->sc_pint = softint_establish(SOFTINT_SERIAL,
172 	    cs4231_sbus_pint, sbsc);
173 	sbsc->sc_rint = softint_establish(SOFTINT_SERIAL,
174 	    cs4231_sbus_rint, sbsc);
175 
176 	/*
177 	 * Map my registers in, if they aren't already in virtual
178 	 * address space.
179 	 */
180 	if (sa->sa_npromvaddrs) {
181 		sbus_promaddr_to_handle(sa->sa_bustag,
182 			sa->sa_promvaddrs[0], &bh);
183 	} else {
184 		if (sbus_bus_map(sa->sa_bustag,	sa->sa_slot,
185 			sa->sa_offset, sa->sa_size, 0, &bh) != 0) {
186 			printf("%s @ sbus: cannot map registers\n",
187 				self->dv_xname);
188 			return;
189 		}
190 	}
191 
192 	bus_space_subregion(sa->sa_bustag, bh, CS4231_APCDMA_OFFSET,
193 		APC_DMA_SIZE, &sbsc->sc_bh);
194 
195 	cs4231_common_attach(sc, bh);
196 	printf("\n");
197 
198 	sbus_establish(&sbsc->sc_sd, &sc->sc_ad1848.sc_dev);
199 
200 	/* Establish interrupt channel */
201 	if (sa->sa_nintr)
202 		bus_intr_establish(sa->sa_bustag,
203 				   sa->sa_pri, IPL_SCHED,
204 				   cs4231_sbus_intr, sbsc);
205 
206 	audio_attach_mi(&audiocs_sbus_hw_if, sbsc, &sc->sc_ad1848.sc_dev);
207 }
208 
209 
210 #ifdef AUDIO_DEBUG
211 static void
212 cs4231_sbus_regdump(char *label, struct cs4231_sbus_softc *sc)
213 {
214 	char bits[128];
215 
216 	printf("cs4231regdump(%s): regs:", label);
217 	printf("dmapva: 0x%x; ",
218 		bus_space_read_4(sc->sc_bh, sc->sc_bh, APC_DMA_PVA));
219 	printf("dmapc: 0x%x; ",
220 		bus_space_read_4(sc->sc_bh, sc->sc_bh, APC_DMA_PC));
221 	printf("dmapnva: 0x%x; ",
222 		bus_space_read_4(sc->sc_bh, sc->sc_bh, APC_DMA_PNVA));
223 	printf("dmapnc: 0x%x\n",
224 		bus_space_read_4(sc->sc_bh, sc->sc_bh, APC_DMA_PNC));
225 	printf("dmacva: 0x%x; ",
226 		bus_space_read_4(sc->sc_bh, sc->sc_bh, APC_DMA_CVA));
227 	printf("dmacc: 0x%x; ",
228 		bus_space_read_4(sc->sc_bh, sc->sc_bh, APC_DMA_CC));
229 	printf("dmacnva: 0x%x; ",
230 		bus_space_read_4(sc->sc_bh, sc->sc_bh, APC_DMA_CNVA));
231 	printf("dmacnc: 0x%x\n",
232 		bus_space_read_4(sc->sc_bh, sc->sc_bh, APC_DMA_CNC));
233 
234 	printf("apc_dmacsr=%s\n",
235 		bitmask_snprintf(
236 			bus_space_read_4(sc->sc_bh, sc->sc_bh, APC_DMA_CSR),
237 				APC_BITS, bits, sizeof(bits)));
238 
239 	ad1848_dump_regs(&sc->sc_cs4231.sc_ad1848);
240 }
241 #endif /* AUDIO_DEBUG */
242 
243 
244 static int
245 cs4231_sbus_trigger_output(void *addr, void *start, void *end, int blksize,
246 			   void (*intr)(void *), void *arg,
247 			   const audio_params_t *param)
248 {
249 	struct cs4231_sbus_softc *sbsc;
250 	struct cs4231_softc *sc;
251 	struct cs_transfer *t;
252 	uint32_t csr;
253 	bus_addr_t dmaaddr;
254 	bus_size_t dmasize;
255 	int ret;
256 #ifdef AUDIO_DEBUG
257 	char bits[128];
258 #endif
259 
260 	sbsc = addr;
261 	sc = &sbsc->sc_cs4231;
262 	t = &sc->sc_playback;
263 	ret = cs4231_transfer_init(sc, t, &dmaaddr, &dmasize,
264 				   start, end, blksize, intr, arg);
265 	if (ret != 0)
266 		return ret;
267 
268 	DPRINTF(("trigger_output: was: %x %d, %x %d\n",
269 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PVA),
270 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PC),
271 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PNVA),
272 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PNC)));
273 
274 	/* load first block */
275 	bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PNVA, dmaaddr);
276 	bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PNC, dmasize);
277 
278 	DPRINTF(("trigger_output: 1st: %x %d, %x %d\n",
279 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PVA),
280 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PC),
281 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PNVA),
282 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PNC)));
283 
284 	csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR);
285 	DPRINTF(("trigger_output: csr=%s\n",
286 		 bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits))));
287 	if ((csr & PDMA_GO) == 0 || (csr & APC_PPAUSE) != 0) {
288 		int cfg;
289 
290 		csr &= ~(APC_PPAUSE | APC_PMIE | APC_INTR_MASK);
291 		bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR, csr);
292 
293 		csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR);
294 		csr &= ~APC_INTR_MASK;
295 		csr |= APC_ENABLE | APC_PIE | APC_PMIE | PDMA_GO;
296 		bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR, csr);
297 
298 		ad_write(&sc->sc_ad1848, SP_LOWER_BASE_COUNT, 0xff);
299 		ad_write(&sc->sc_ad1848, SP_UPPER_BASE_COUNT, 0xff);
300 
301 		cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
302 		ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG,
303 			 (cfg | PLAYBACK_ENABLE));
304 	} else {
305 		DPRINTF(("trigger_output: already: csr=%s\n",
306 			 bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits))));
307 	}
308 
309 	/* load next block if we can */
310 	csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR);
311 	if (csr & APC_PD) {
312 		cs4231_transfer_advance(t, &dmaaddr, &dmasize);
313 		bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PNVA, dmaaddr);
314 		bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PNC, dmasize);
315 
316 		DPRINTF(("trigger_output: 2nd: %x %d, %x %d\n",
317 		    bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PVA),
318 		    bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PC),
319 		    bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PNVA),
320 		    bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_PNC)));
321 	}
322 
323 	return 0;
324 }
325 
326 
327 static int
328 cs4231_sbus_halt_output(void *addr)
329 {
330 	struct cs4231_sbus_softc *sbsc;
331 	struct cs4231_softc *sc;
332 	uint32_t csr;
333 	int cfg;
334 #ifdef AUDIO_DEBUG
335 	char bits[128];
336 #endif
337 
338 	sbsc = addr;
339 	sc = &sbsc->sc_cs4231;
340 	sc->sc_playback.t_active = 0;
341 
342 	csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR);
343 	DPRINTF(("halt_output: csr=%s\n",
344 		 bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits))));
345 
346 	csr &= ~APC_INTR_MASK;	/* do not clear interrupts accidentally */
347 	csr |= APC_PPAUSE;	/* pause playback (let current complete) */
348 	bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR, csr);
349 
350 	/* let the curernt transfer complete */
351 	if (csr & PDMA_GO)
352 		do {
353 			csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh,
354 				APC_DMA_CSR);
355 			DPRINTF(("halt_output: csr=%s\n",
356 				 bitmask_snprintf(csr, APC_BITS,
357 						  bits, sizeof(bits))));
358 		} while ((csr & APC_PM) == 0);
359 
360 	cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
361 	ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG,(cfg & ~PLAYBACK_ENABLE));
362 
363 	return 0;
364 }
365 
366 
367 /* NB: we don't enable APC_CMIE and won't use APC_CM */
368 static int
369 cs4231_sbus_trigger_input(void *addr, void *start, void *end, int blksize,
370 			  void (*intr)(void *), void *arg,
371 			  const audio_params_t *param)
372 {
373 	struct cs4231_sbus_softc *sbsc;
374 	struct cs4231_softc *sc;
375 	struct cs_transfer *t;
376 	uint32_t csr;
377 	bus_addr_t dmaaddr;
378 	bus_size_t dmasize;
379 	int ret;
380 #ifdef AUDIO_DEBUG
381 	char bits[128];
382 #endif
383 
384 	sbsc = addr;
385 	sc = &sbsc->sc_cs4231;
386 	t = &sc->sc_capture;
387 	ret = cs4231_transfer_init(sc, t, &dmaaddr, &dmasize,
388 				   start, end, blksize, intr, arg);
389 	if (ret != 0)
390 		return ret;
391 
392 	csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR);
393 	DPRINTF(("trigger_input: csr=%s\n",
394 		 bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits))));
395 	DPRINTF(("trigger_input: was: %x %d, %x %d\n",
396 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CVA),
397 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CC),
398 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CNVA),
399 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CNC)));
400 
401 	/* supply first block */
402 	bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CNVA, dmaaddr);
403 	bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CNC, dmasize);
404 
405 	DPRINTF(("trigger_input: 1st: %x %d, %x %d\n",
406 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CVA),
407 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CC),
408 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CNVA),
409 		bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CNC)));
410 
411 	csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR);
412 	if ((csr & CDMA_GO) == 0 || (csr & APC_CPAUSE) != 0) {
413 		int cfg;
414 
415 		csr &= ~(APC_CPAUSE | APC_CMIE | APC_INTR_MASK);
416 		bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR, csr);
417 
418 		csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR);
419 		csr &= ~APC_INTR_MASK;
420 		csr |= APC_ENABLE | APC_CIE | CDMA_GO;
421 		bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR, csr);
422 
423 		ad_write(&sc->sc_ad1848, CS_LOWER_REC_CNT, 0xff);
424 		ad_write(&sc->sc_ad1848, CS_UPPER_REC_CNT, 0xff);
425 
426 		cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
427 		ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG,
428 			 (cfg | CAPTURE_ENABLE));
429 	} else {
430 		DPRINTF(("trigger_input: already: csr=%s\n",
431 			 bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits))));
432 	}
433 
434 	/* supply next block if we can */
435 	csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR);
436 	if (csr & APC_CD) {
437 		cs4231_transfer_advance(t, &dmaaddr, &dmasize);
438 		bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CNVA, dmaaddr);
439 		bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CNC, dmasize);
440 		DPRINTF(("trigger_input: 2nd: %x %d, %x %d\n",
441 		    bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CVA),
442 		    bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CC),
443 		    bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CNVA),
444 		    bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CNC)));
445 	}
446 
447 	return 0;
448 }
449 
450 
451 static int
452 cs4231_sbus_halt_input(void *addr)
453 {
454 	struct cs4231_sbus_softc *sbsc;
455 	struct cs4231_softc *sc;
456 	uint32_t csr;
457 	int cfg;
458 #ifdef AUDIO_DEBUG
459 	char bits[128];
460 #endif
461 
462 	sbsc = addr;
463 	sc = &sbsc->sc_cs4231;
464 	sc->sc_capture.t_active = 0;
465 
466 	csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR);
467 	DPRINTF(("halt_input: csr=%s\n",
468 		 bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits))));
469 
470 	csr &= ~APC_INTR_MASK;	/* do not clear interrupts accidentally */
471 	csr |= APC_CPAUSE;
472 	bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR, csr);
473 
474 	/* let the curernt transfer complete */
475 	if (csr & CDMA_GO)
476 		do {
477 			csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh,
478 				APC_DMA_CSR);
479 			DPRINTF(("halt_input: csr=%s\n",
480 				 bitmask_snprintf(csr, APC_BITS,
481 						  bits, sizeof(bits))));
482 		} while ((csr & APC_CM) == 0);
483 
484 	cfg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG);
485 	ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, (cfg & ~CAPTURE_ENABLE));
486 
487 	return 0;
488 }
489 
490 
491 static int
492 cs4231_sbus_intr(void *arg)
493 {
494 	struct cs4231_sbus_softc *sbsc;
495 	struct cs4231_softc *sc;
496 	uint32_t csr;
497 	int status;
498 	bus_addr_t dmaaddr;
499 	bus_size_t dmasize;
500 	int served;
501 #if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
502 	char bits[128];
503 #endif
504 
505 	sbsc = arg;
506 	sc = &sbsc->sc_cs4231;
507 	csr = bus_space_read_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR);
508 	if ((csr & APC_INTR_MASK) == 0)	/* any interrupt pedning? */
509 		return 0;
510 
511 	/* write back DMA status to clear interrupt */
512 	bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR, csr);
513 	++sc->sc_intrcnt.ev_count;
514 	served = 0;
515 
516 #ifdef AUDIO_DEBUG
517 	if (cs4231_sbus_debug > 1)
518 		cs4231_sbus_regdump("audiointr", sbsc);
519 #endif
520 
521 	status = ADREAD(&sc->sc_ad1848, AD1848_STATUS);
522 	DPRINTF(("%s: status: %s\n", sc->sc_ad1848.sc_dev.dv_xname,
523 		bitmask_snprintf(status, AD_R2_BITS, bits, sizeof(bits))));
524 	if (status & INTERRUPT_STATUS) {
525 #ifdef AUDIO_DEBUG
526 		int reason;
527 
528 		reason = ad_read(&sc->sc_ad1848, CS_IRQ_STATUS);
529 		DPRINTF(("%s: i24: %s\n", sc->sc_ad1848.sc_dev.dv_xname,
530 		  bitmask_snprintf(reason, CS_I24_BITS, bits, sizeof(bits))));
531 #endif
532 		/* clear ad1848 interrupt */
533 		ADWRITE(&sc->sc_ad1848, AD1848_STATUS, 0);
534 	}
535 
536 	if (csr & APC_CI) {
537 		if (csr & APC_CD) { /* can supply new block */
538 			struct cs_transfer *t = &sc->sc_capture;
539 
540 			cs4231_transfer_advance(t, &dmaaddr, &dmasize);
541 			bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh,
542 				APC_DMA_CNVA, dmaaddr);
543 			bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh,
544 				APC_DMA_CNC, dmasize);
545 
546 			if (t->t_intr != NULL)
547 				softint_schedule(sbsc->sc_rint);
548 			++t->t_intrcnt.ev_count;
549 			served = 1;
550 		}
551 	}
552 
553 	if (csr & APC_PMI) {
554 		if (!sc->sc_playback.t_active)
555 			served = 1; /* draining in halt_output() */
556 	}
557 
558 	if (csr & APC_PI) {
559 		if (csr & APC_PD) { /* can load new block */
560 			struct cs_transfer *t = &sc->sc_playback;
561 
562 			if (t->t_active) {
563 				cs4231_transfer_advance(t, &dmaaddr, &dmasize);
564 				bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh,
565 					APC_DMA_PNVA, dmaaddr);
566 				bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh,
567 					APC_DMA_PNC, dmasize);
568 			}
569 
570 			if (t->t_intr != NULL)
571 				softint_schedule(sbsc->sc_pint);
572 			++t->t_intrcnt.ev_count;
573 			served = 1;
574 		}
575 	}
576 
577 	/* got an interrupt we don't know how to handle */
578 	if (!served) {
579 #ifdef DIAGNOSTIC
580 		printf("%s: unhandled csr=%s\n", sc->sc_ad1848.sc_dev.dv_xname,
581 		       bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits)));
582 #endif
583 		/* evcnt? */
584 	}
585 
586 	return 1;
587 }
588 
589 static void
590 cs4231_sbus_pint(void *cookie)
591 {
592 	struct cs4231_softc *sc = cookie;
593 	struct cs_transfer *t = &sc->sc_playback;
594 
595 	if (t->t_intr != NULL)
596 		(*t->t_intr)(t->t_arg);
597 }
598 
599 static void
600 cs4231_sbus_rint(void *cookie)
601 {
602 	struct cs4231_softc *sc = cookie;
603 	struct cs_transfer *t = &sc->sc_capture;
604 
605 	if (t->t_intr != NULL)
606 		(*t->t_intr)(t->t_arg);
607 }
608 
609 #endif /* NAUDIO > 0 */
610