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