1*df83eae3Sskrll /* $NetBSD: vraiu.c,v 1.20 2021/01/13 06:39:46 skrll Exp $ */
2fddeb95fShamajima
3fddeb95fShamajima /*
4fddeb95fShamajima * Copyright (c) 2001 HAMAJIMA Katsuomi. All rights reserved.
5fddeb95fShamajima *
6fddeb95fShamajima * Redistribution and use in source and binary forms, with or without
7fddeb95fShamajima * modification, are permitted provided that the following conditions
8fddeb95fShamajima * are met:
9fddeb95fShamajima * 1. Redistributions of source code must retain the above copyright
10fddeb95fShamajima * notice, this list of conditions and the following disclaimer.
11fddeb95fShamajima * 2. Redistributions in binary form must reproduce the above copyright
12fddeb95fShamajima * notice, this list of conditions and the following disclaimer in the
13fddeb95fShamajima * documentation and/or other materials provided with the distribution.
14fddeb95fShamajima *
15fddeb95fShamajima * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16fddeb95fShamajima * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17fddeb95fShamajima * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18fddeb95fShamajima * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19fddeb95fShamajima * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20fddeb95fShamajima * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21fddeb95fShamajima * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22fddeb95fShamajima * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23fddeb95fShamajima * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24fddeb95fShamajima * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25fddeb95fShamajima * SUCH DAMAGE.
26fddeb95fShamajima */
27fddeb95fShamajima
280c82163cSlukem #include <sys/cdefs.h>
29*df83eae3Sskrll __KERNEL_RCSID(0, "$NetBSD: vraiu.c,v 1.20 2021/01/13 06:39:46 skrll Exp $");
300c82163cSlukem
31fddeb95fShamajima #include <sys/param.h>
32fddeb95fShamajima #include <sys/systm.h>
33fddeb95fShamajima #include <sys/device.h>
34fddeb95fShamajima #include <sys/bswap.h>
35fddeb95fShamajima
36fddeb95fShamajima #include <machine/cpu.h>
37fddeb95fShamajima #include <machine/intr.h>
38fddeb95fShamajima #include <machine/bus.h>
39fddeb95fShamajima #include <machine/platid.h>
40fddeb95fShamajima #include <machine/platid_mask.h>
41fddeb95fShamajima #include <machine/config_hook.h>
42fddeb95fShamajima
43fddeb95fShamajima #include <sys/audioio.h>
44e622eac4Sisaki #include <dev/audio/audio_if.h>
45fddeb95fShamajima
46fddeb95fShamajima #include <hpcmips/vr/vr.h>
47fddeb95fShamajima #include <hpcmips/vr/vripif.h>
48fddeb95fShamajima #include <hpcmips/vr/icureg.h>
49fddeb95fShamajima #include <hpcmips/vr/cmureg.h>
50fddeb95fShamajima #include <hpcmips/vr/vraiureg.h>
51fddeb95fShamajima
52fddeb95fShamajima #ifdef VRAIU_DEBUG
53fddeb95fShamajima int vraiu_debug = VRAIU_DEBUG;
54fddeb95fShamajima #define DPRINTFN(n,x) if (vraiu_debug>(n)) printf x;
55fddeb95fShamajima #else
56fddeb95fShamajima #define DPRINTFN(n,x)
57fddeb95fShamajima #endif
58fddeb95fShamajima
59fddeb95fShamajima #define AUDIO_BUF_SIZE 2048
60fddeb95fShamajima
61fddeb95fShamajima struct vraiu_softc {
62cbab9cadSchs device_t sc_dev;
638a962f23Sjmcneill kmutex_t sc_lock;
648a962f23Sjmcneill kmutex_t sc_intr_lock;
65fddeb95fShamajima bus_space_tag_t sc_iot;
66fddeb95fShamajima bus_space_handle_t sc_ioh;
67fddeb95fShamajima bus_dma_tag_t sc_dmat;
68fddeb95fShamajima bus_dmamap_t sc_dmap;
69fddeb95fShamajima vrip_chipset_tag_t sc_vrip;
70fddeb95fShamajima vrdcu_chipset_tag_t sc_dc;
71fddeb95fShamajima vrdmaau_chipset_tag_t sc_ac;
72fddeb95fShamajima vrcmu_chipset_tag_t sc_cc;
73fddeb95fShamajima void *sc_handler;
741ffa7b76Swiz u_short *sc_buf; /* DMA buffer pointer */
75fddeb95fShamajima u_int sc_rate; /* sampling rate */
768c56c583Sjmcneill u_char sc_volume; /* volume */
77fddeb95fShamajima void (*sc_intr)(void *); /* interrupt routine */
78fddeb95fShamajima void *sc_intrdata; /* interrupt data */
79fddeb95fShamajima };
80fddeb95fShamajima
81cbab9cadSchs int vraiu_match(device_t, cfdata_t, void *);
82cbab9cadSchs void vraiu_attach(device_t, device_t, void *);
83fddeb95fShamajima int vraiu_intr(void *);
84fddeb95fShamajima
85cbab9cadSchs CFATTACH_DECL_NEW(vraiu, sizeof(struct vraiu_softc),
86c5e91d44Sthorpej vraiu_match, vraiu_attach, NULL, NULL);
87fddeb95fShamajima
88fddeb95fShamajima struct audio_device aiu_device = {
89fddeb95fShamajima "VR4121 AIU",
90fddeb95fShamajima "0.1",
91fddeb95fShamajima "aiu"
92fddeb95fShamajima };
93fddeb95fShamajima
94e622eac4Sisaki const struct audio_format vraiu_formats = {
95e622eac4Sisaki .mode = AUMODE_PLAY,
96e622eac4Sisaki .encoding = AUDIO_ENCODING_SLINEAR_NE,
97e622eac4Sisaki .validbits = 10,
98e622eac4Sisaki .precision = 16,
99e622eac4Sisaki .channels = 1,
100e622eac4Sisaki .channel_mask = AUFMT_MONAURAL,
101e622eac4Sisaki .frequency_type = 4,
102e622eac4Sisaki .frequency = { 8000, 11025, 22050, 44100 },
103e622eac4Sisaki };
104e622eac4Sisaki
105fddeb95fShamajima /*
106fddeb95fShamajima * Define our interface to the higher level audio driver.
107fddeb95fShamajima */
108e622eac4Sisaki int vraiu_query_format(void *, audio_format_query_t *);
10923b5d914Skent int vraiu_round_blocksize(void *, int, int, const audio_params_t *);
110fddeb95fShamajima int vraiu_commit_settings(void *);
111fddeb95fShamajima int vraiu_init_output(void *, void*, int);
112fddeb95fShamajima int vraiu_start_output(void *, void *, int, void (*)(void *), void *);
113fddeb95fShamajima int vraiu_halt_output(void *);
114fddeb95fShamajima int vraiu_getdev(void *, struct audio_device *);
115fddeb95fShamajima int vraiu_set_port(void *, mixer_ctrl_t *);
116fddeb95fShamajima int vraiu_get_port(void *, mixer_ctrl_t *);
117fddeb95fShamajima int vraiu_query_devinfo(void *, mixer_devinfo_t *);
118e622eac4Sisaki int vraiu_set_format(void *, int,
119e622eac4Sisaki const audio_params_t *, const audio_params_t *,
120e622eac4Sisaki audio_filter_reg_t *, audio_filter_reg_t *);
121fddeb95fShamajima int vraiu_get_props(void *);
1228a962f23Sjmcneill void vraiu_get_locks(void *, kmutex_t **, kmutex_t **);
123fddeb95fShamajima
12418f717bbSyamt const struct audio_hw_if vraiu_hw_if = {
125e622eac4Sisaki .query_format = vraiu_query_format,
126e622eac4Sisaki .set_format = vraiu_set_format,
1276291b134Sisaki .round_blocksize = vraiu_round_blocksize,
1286291b134Sisaki .commit_settings = vraiu_commit_settings,
1296291b134Sisaki .init_output = vraiu_init_output,
1306291b134Sisaki .start_output = vraiu_start_output,
1316291b134Sisaki .halt_output = vraiu_halt_output,
1326291b134Sisaki .getdev = vraiu_getdev,
1336291b134Sisaki .set_port = vraiu_set_port,
1346291b134Sisaki .get_port = vraiu_get_port,
1356291b134Sisaki .query_devinfo = vraiu_query_devinfo,
1366291b134Sisaki .get_props = vraiu_get_props,
1376291b134Sisaki .get_locks = vraiu_get_locks,
138fddeb95fShamajima };
139fddeb95fShamajima
140fddeb95fShamajima /*
141fddeb95fShamajima * convert to 1ch 10bit unsigned PCM data.
142fddeb95fShamajima */
143fddeb95fShamajima static void vraiu_slinear16_1(struct vraiu_softc *, u_short *, void *, int);
144fddeb95fShamajima
145fddeb95fShamajima int
vraiu_match(device_t parent,cfdata_t cf,void * aux)146cbab9cadSchs vraiu_match(device_t parent, cfdata_t cf, void *aux)
147fddeb95fShamajima {
148fddeb95fShamajima return 1;
149fddeb95fShamajima }
150fddeb95fShamajima
151fddeb95fShamajima void
vraiu_attach(device_t parent,device_t self,void * aux)152cbab9cadSchs vraiu_attach(device_t parent, device_t self, void *aux)
153fddeb95fShamajima {
15493293b9eSkent struct vrip_attach_args *va;
15593293b9eSkent struct vraiu_softc *sc;
156fddeb95fShamajima bus_dma_segment_t segs;
157fddeb95fShamajima int rsegs;
158fddeb95fShamajima
15993293b9eSkent va = aux;
160cbab9cadSchs sc = device_private(self);
161cbab9cadSchs sc->sc_dev = self;
162fddeb95fShamajima sc->sc_intr = NULL;
163fddeb95fShamajima sc->sc_iot = va->va_iot;
164fddeb95fShamajima sc->sc_vrip = va->va_vc;
165fddeb95fShamajima sc->sc_cc = va->va_cc;
166fddeb95fShamajima sc->sc_dc = va->va_dc;
167fddeb95fShamajima sc->sc_ac = va->va_ac;
168fddeb95fShamajima sc->sc_dmat = &vrdcu_bus_dma_tag;
1698c56c583Sjmcneill sc->sc_volume = 127;
1708a962f23Sjmcneill mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
1718de08fa9Smrg mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
172fddeb95fShamajima
173fddeb95fShamajima if (!sc->sc_cc) {
174fddeb95fShamajima printf(" not configured: cmu not found\n");
175fddeb95fShamajima return;
176fddeb95fShamajima }
177fddeb95fShamajima if (!sc->sc_dc) {
178fddeb95fShamajima printf(" not configured: dcu not found\n");
179fddeb95fShamajima return;
180fddeb95fShamajima }
181fddeb95fShamajima if (!sc->sc_ac) {
182fddeb95fShamajima printf(" not configured: dmaau not found\n");
183fddeb95fShamajima return;
184fddeb95fShamajima }
185fddeb95fShamajima if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size,
186fddeb95fShamajima 0 /* no flags */, &sc->sc_ioh)) {
187fddeb95fShamajima printf(": can't map i/o space\n");
188fddeb95fShamajima return;
189fddeb95fShamajima }
190fddeb95fShamajima
191fddeb95fShamajima /* install interrupt handler and enable interrupt */
192fddeb95fShamajima if (!(sc->sc_handler = vrip_intr_establish(va->va_vc, va->va_unit,
1938de08fa9Smrg 0, IPL_AUDIO, vraiu_intr, sc))) {
194fddeb95fShamajima printf(": can't map interrupt line.\n");
195fddeb95fShamajima return;
196fddeb95fShamajima }
197fddeb95fShamajima vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, (AIUINT_INTMEND | \
198fddeb95fShamajima AIUINT_INTM | \
199fddeb95fShamajima AIUINT_INTMIDLE | \
200fddeb95fShamajima AIUINT_INTMST | \
201fddeb95fShamajima AIUINT_INTSEND | \
202fddeb95fShamajima AIUINT_INTS | \
203fddeb95fShamajima AIUINT_INTSIDLE), 0);
204fddeb95fShamajima
205fddeb95fShamajima if (bus_dmamem_alloc(sc->sc_dmat, AUDIO_BUF_SIZE, 0, 0, &segs, 1,
2068a962f23Sjmcneill &rsegs, BUS_DMA_WAITOK)) {
207fddeb95fShamajima printf(": can't allocate memory.\n");
208fddeb95fShamajima return;
209fddeb95fShamajima }
210fddeb95fShamajima if (bus_dmamem_map(sc->sc_dmat, &segs, rsegs, AUDIO_BUF_SIZE,
21153524e44Schristos (void **)&sc->sc_buf,
2128a962f23Sjmcneill BUS_DMA_WAITOK | BUS_DMA_COHERENT)) {
213fddeb95fShamajima printf(": can't map memory.\n");
214fddeb95fShamajima bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
215fddeb95fShamajima return;
216fddeb95fShamajima }
217fddeb95fShamajima if (bus_dmamap_create(sc->sc_dmat, AUDIO_BUF_SIZE, 1, AUDIO_BUF_SIZE,
2188a962f23Sjmcneill 0, BUS_DMA_WAITOK, &sc->sc_dmap)) {
219fddeb95fShamajima printf(": can't create DMA map.\n");
22053524e44Schristos bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
221fddeb95fShamajima AUDIO_BUF_SIZE);
222fddeb95fShamajima bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
223fddeb95fShamajima return;
224fddeb95fShamajima }
225fddeb95fShamajima if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, sc->sc_buf,
2268a962f23Sjmcneill AUDIO_BUF_SIZE, NULL, BUS_DMA_WAITOK)) {
227fddeb95fShamajima printf(": can't load DMA map.\n");
228fddeb95fShamajima bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
22953524e44Schristos bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
230fddeb95fShamajima AUDIO_BUF_SIZE);
231fddeb95fShamajima bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
232fddeb95fShamajima return;
233fddeb95fShamajima }
234fddeb95fShamajima if (sc->sc_ac->ac_set_aiuout(sc->sc_ac, sc->sc_buf)) {
235fddeb95fShamajima printf(": can't set DMA address.\n");
236fddeb95fShamajima bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
237fddeb95fShamajima bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
23853524e44Schristos bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
239fddeb95fShamajima AUDIO_BUF_SIZE);
240fddeb95fShamajima bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
241fddeb95fShamajima return;
242fddeb95fShamajima }
243fddeb95fShamajima printf("\n");
244fddeb95fShamajima
245fddeb95fShamajima sc->sc_rate = SPS8000;
246fddeb95fShamajima DPRINTFN(1, ("vraiu_attach: reset AIU\n"))
247fddeb95fShamajima bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIURST);
248fddeb95fShamajima /* attach audio subsystem */
249cbab9cadSchs audio_attach_mi(&vraiu_hw_if, sc, self);
250fddeb95fShamajima }
251fddeb95fShamajima
252fddeb95fShamajima int
vraiu_query_format(void * self,audio_format_query_t * afp)253e622eac4Sisaki vraiu_query_format(void *self, audio_format_query_t *afp)
254fddeb95fShamajima {
255fddeb95fShamajima
256e622eac4Sisaki return audio_query_format(&vraiu_formats, 1, afp);
257fddeb95fShamajima }
258fddeb95fShamajima
259fddeb95fShamajima int
vraiu_set_format(void * self,int setmode,const audio_params_t * play,const audio_params_t * rec,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)260e622eac4Sisaki vraiu_set_format(void *self, int setmode,
261e622eac4Sisaki const audio_params_t *play, const audio_params_t *rec,
262e622eac4Sisaki audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
263fddeb95fShamajima {
26493293b9eSkent struct vraiu_softc *sc;
265fddeb95fShamajima
266e622eac4Sisaki DPRINTFN(1, ("%s: %ubit, %uch, %uHz, encoding %u\n", __func__,
267fddeb95fShamajima play->precision, play->channels, play->sample_rate,
268fddeb95fShamajima play->encoding));
26993293b9eSkent sc = self;
270e622eac4Sisaki
271fddeb95fShamajima switch (play->sample_rate) {
272fddeb95fShamajima case 8000:
273fddeb95fShamajima sc->sc_rate = SPS8000;
274fddeb95fShamajima break;
275fddeb95fShamajima case 11025:
276fddeb95fShamajima sc->sc_rate = SPS11025;
277fddeb95fShamajima break;
278fddeb95fShamajima case 22050:
279fddeb95fShamajima sc->sc_rate = SPS22050;
280fddeb95fShamajima break;
281fddeb95fShamajima case 44100:
282fddeb95fShamajima sc->sc_rate = SPS44100;
283fddeb95fShamajima break;
284fddeb95fShamajima default:
285e622eac4Sisaki /* NOTREACHED */
286e622eac4Sisaki panic("%s: rate error (%d)\n", __func__, play->sample_rate);
287fddeb95fShamajima }
288fddeb95fShamajima
289fddeb95fShamajima return 0;
290fddeb95fShamajima }
291fddeb95fShamajima
292fddeb95fShamajima int
vraiu_round_blocksize(void * self,int bs,int mode,const audio_params_t * param)29323b5d914Skent vraiu_round_blocksize(void *self, int bs, int mode, const audio_params_t *param)
294fddeb95fShamajima {
295e622eac4Sisaki return AUDIO_BUF_SIZE;
296fddeb95fShamajima }
297fddeb95fShamajima
298fddeb95fShamajima int
vraiu_commit_settings(void * self)299fddeb95fShamajima vraiu_commit_settings(void *self)
300fddeb95fShamajima {
30193293b9eSkent struct vraiu_softc *sc;
302fddeb95fShamajima int err;
303fddeb95fShamajima
304fddeb95fShamajima DPRINTFN(1, ("vraiu_commit_settings\n"));
30593293b9eSkent sc = self;
306fddeb95fShamajima
307fddeb95fShamajima DPRINTFN(1, ("vraiu_commit_settings: set conversion rate %d\n",
308fddeb95fShamajima sc->sc_rate))
309fddeb95fShamajima bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNVR_REG_W, sc->sc_rate);
310fddeb95fShamajima DPRINTFN(1, ("vraiu_commit_settings: clock supply start\n"))
311fddeb95fShamajima if ((err = sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 1))) {
312fddeb95fShamajima DPRINTFN(0, ("vraiu_commit_settings: clock supply error\n"));
313fddeb95fShamajima return err;
314fddeb95fShamajima }
315fddeb95fShamajima DPRINTFN(1, ("vraiu_commit_settings: enable DMA\n"))
316fddeb95fShamajima if ((err = sc->sc_dc->dc_enable_aiuout(sc->sc_dc))) {
317fddeb95fShamajima sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
3181ffa7b76Swiz DPRINTFN(0, ("vraiu_commit_settings: enable DMA error\n"));
319fddeb95fShamajima return err;
320fddeb95fShamajima }
321fddeb95fShamajima DPRINTFN(1, ("vraiu_commit_settings: Vref on\n"))
322fddeb95fShamajima bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, DAENAIU);
323fddeb95fShamajima return 0;
324fddeb95fShamajima }
325fddeb95fShamajima
326fddeb95fShamajima int
vraiu_init_output(void * self,void * buffer,int size)327fddeb95fShamajima vraiu_init_output(void *self, void *buffer, int size)
328fddeb95fShamajima {
32993293b9eSkent struct vraiu_softc *sc;
330fddeb95fShamajima
331fddeb95fShamajima DPRINTFN(1, ("vraiu_init_output: buffer %p, size %d\n", buffer, size));
33293293b9eSkent sc = self;
333fddeb95fShamajima sc->sc_intr = NULL;
334fddeb95fShamajima DPRINTFN(1, ("vraiu_init_output: speaker power on\n"))
335fddeb95fShamajima config_hook_call(CONFIG_HOOK_POWERCONTROL,
336fddeb95fShamajima CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)1);
337fddeb95fShamajima DPRINTFN(1, ("vraiu_init_output: start output\n"))
338fddeb95fShamajima bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIUSEN);
339fddeb95fShamajima return 0;
340fddeb95fShamajima }
341fddeb95fShamajima
342fddeb95fShamajima int
vraiu_start_output(void * self,void * block,int bsize,void (* intr)(void *),void * intrarg)343fddeb95fShamajima vraiu_start_output(void *self, void *block, int bsize,
344fddeb95fShamajima void (*intr)(void *), void *intrarg)
345fddeb95fShamajima {
34693293b9eSkent struct vraiu_softc *sc;
347fddeb95fShamajima
348fddeb95fShamajima DPRINTFN(2, ("vraiu_start_output: block %p, bsize %d\n",
349fddeb95fShamajima block, bsize));
35093293b9eSkent sc = self;
351e622eac4Sisaki vraiu_slinear16_1(sc, sc->sc_buf, block, bsize);
352fddeb95fShamajima bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, AUDIO_BUF_SIZE,
353fddeb95fShamajima BUS_DMASYNC_PREWRITE);
354fddeb95fShamajima sc->sc_intr = intr;
355fddeb95fShamajima sc->sc_intrdata = intrarg;
356fddeb95fShamajima /* clear interrupt status */
357fddeb95fShamajima bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W,
358fddeb95fShamajima SENDINTR | SINTR | SIDLEINTR);
359fddeb95fShamajima /* enable interrupt */
360fddeb95fShamajima vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 1);
361fddeb95fShamajima return 0;
362fddeb95fShamajima }
363fddeb95fShamajima
364fddeb95fShamajima int
vraiu_intr(void * self)365fddeb95fShamajima vraiu_intr(void* self)
366fddeb95fShamajima {
36793293b9eSkent struct vraiu_softc *sc;
36893293b9eSkent uint32_t reg;
369fddeb95fShamajima
370fddeb95fShamajima DPRINTFN(2, ("vraiu_intr"));
37193293b9eSkent sc = self;
3728a962f23Sjmcneill
3738a962f23Sjmcneill mutex_spin_enter(&sc->sc_intr_lock);
3748a962f23Sjmcneill
375fddeb95fShamajima vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
376fddeb95fShamajima vrip_intr_getstatus2(sc->sc_vrip, sc->sc_handler, ®);
377fddeb95fShamajima if (reg & AIUINT_INTSEND) {
378fddeb95fShamajima DPRINTFN(2, (": AIUINT_INTSEND"));
379fddeb95fShamajima if (sc->sc_intr) {
38093293b9eSkent void (*intr)(void *);
38193293b9eSkent intr = sc->sc_intr;
382fddeb95fShamajima sc->sc_intr = NULL;
383fddeb95fShamajima (*(intr))(sc->sc_intrdata);
384fddeb95fShamajima }
385fddeb95fShamajima bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W, SENDINTR);
386fddeb95fShamajima }
387fddeb95fShamajima DPRINTFN(2, ("\n"));
3888a962f23Sjmcneill
3898a962f23Sjmcneill mutex_spin_exit(&sc->sc_intr_lock);
3908a962f23Sjmcneill
391fddeb95fShamajima return 0;
392fddeb95fShamajima }
393fddeb95fShamajima
394fddeb95fShamajima int
vraiu_halt_output(void * self)395fddeb95fShamajima vraiu_halt_output(void *self)
396fddeb95fShamajima {
39793293b9eSkent struct vraiu_softc *sc;
398fddeb95fShamajima
399fddeb95fShamajima DPRINTFN(1, ("vraiu_halt_output\n"));
40093293b9eSkent sc =self;
401fddeb95fShamajima DPRINTFN(1, ("vraiu_halt_output: disable interrupt\n"))
402fddeb95fShamajima vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
403fddeb95fShamajima DPRINTFN(1, ("vraiu_halt_output: stop output\n"))
404fddeb95fShamajima bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, 0);
405fddeb95fShamajima DPRINTFN(1, ("vraiu_halt_output: speaker power off\n"))
406fddeb95fShamajima config_hook_call(CONFIG_HOOK_POWERCONTROL,
407fddeb95fShamajima CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)0);
408fddeb95fShamajima DPRINTFN(1, ("vraiu_halt_output: Vref off\n"))
409fddeb95fShamajima bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, 0);
410fddeb95fShamajima DPRINTFN(1, ("vraiu_halt_output: disable DMA\n"))
411fddeb95fShamajima sc->sc_dc->dc_disable(sc->sc_dc);
412fddeb95fShamajima DPRINTFN(1, ("vraiu_halt_output: clock supply stop\n"))
413fddeb95fShamajima sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
414fddeb95fShamajima sc->sc_intr = NULL;
415fddeb95fShamajima return 0;
416fddeb95fShamajima }
417fddeb95fShamajima
418fddeb95fShamajima int
vraiu_getdev(void * self,struct audio_device * ret)419fddeb95fShamajima vraiu_getdev(void *self, struct audio_device *ret)
420fddeb95fShamajima {
421fddeb95fShamajima
42293293b9eSkent DPRINTFN(3, ("vraiu_getdev\n"));
423fddeb95fShamajima *ret = aiu_device;
424fddeb95fShamajima return 0;
425fddeb95fShamajima }
426fddeb95fShamajima
427fddeb95fShamajima int
vraiu_set_port(void * self,mixer_ctrl_t * mc)428fddeb95fShamajima vraiu_set_port(void *self, mixer_ctrl_t *mc)
429fddeb95fShamajima {
43093293b9eSkent struct vraiu_softc *sc;
431fddeb95fShamajima
43293293b9eSkent DPRINTFN(3, ("vraiu_set_port\n"));
43393293b9eSkent sc = self;
4348c56c583Sjmcneill /* software mixer, 1ch */
4358c56c583Sjmcneill if (mc->dev == 0) {
4368c56c583Sjmcneill if (mc->type != AUDIO_MIXER_VALUE)
4378c56c583Sjmcneill return EINVAL;
4388c56c583Sjmcneill if (mc->un.value.num_channels != 1)
4398c56c583Sjmcneill return EINVAL;
4408c56c583Sjmcneill sc->sc_volume = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
4418c56c583Sjmcneill return 0;
4428c56c583Sjmcneill }
4438c56c583Sjmcneill
444fddeb95fShamajima return EINVAL;
445fddeb95fShamajima }
446fddeb95fShamajima
447fddeb95fShamajima int
vraiu_get_port(void * self,mixer_ctrl_t * mc)448fddeb95fShamajima vraiu_get_port(void *self, mixer_ctrl_t *mc)
449fddeb95fShamajima {
45093293b9eSkent struct vraiu_softc *sc;
451fddeb95fShamajima
45293293b9eSkent DPRINTFN(3, ("vraiu_get_port\n"));
45393293b9eSkent sc = self;
4548c56c583Sjmcneill /* software mixer, 1ch */
4558c56c583Sjmcneill if (mc->dev == 0) {
4568c56c583Sjmcneill if (mc->un.value.num_channels != 1)
4578c56c583Sjmcneill return EINVAL;
4588c56c583Sjmcneill mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_volume;
4598c56c583Sjmcneill return 0;
4608c56c583Sjmcneill }
4618c56c583Sjmcneill
462fddeb95fShamajima return EINVAL;
463fddeb95fShamajima }
464fddeb95fShamajima
465fddeb95fShamajima int
vraiu_query_devinfo(void * self,mixer_devinfo_t * di)466fddeb95fShamajima vraiu_query_devinfo(void *self, mixer_devinfo_t *di)
467fddeb95fShamajima {
468fddeb95fShamajima
46993293b9eSkent DPRINTFN(3, ("vraiu_query_devinfo\n"));
4708c56c583Sjmcneill /* software mixer, 1ch */
4718c56c583Sjmcneill switch (di->index) {
4728c56c583Sjmcneill case 0: /* inputs.dac mixer value */
4738c56c583Sjmcneill di->mixer_class = 1;
4748c56c583Sjmcneill di->next = di->prev = AUDIO_MIXER_LAST;
4758c56c583Sjmcneill strcpy(di->label.name, AudioNdac);
4768c56c583Sjmcneill di->type = AUDIO_MIXER_VALUE;
4778c56c583Sjmcneill di->un.v.num_channels = 1;
4788c56c583Sjmcneill strcpy(di->un.v.units.name, AudioNvolume);
4798c56c583Sjmcneill return 0;
4808c56c583Sjmcneill case 1: /* outputs class */
4818c56c583Sjmcneill di->mixer_class = 1;
4828c56c583Sjmcneill di->next = di->prev = AUDIO_MIXER_LAST;
4838c56c583Sjmcneill strcpy(di->label.name, AudioCinputs);
4848c56c583Sjmcneill di->type = AUDIO_MIXER_CLASS;
4858c56c583Sjmcneill return 0;
4868c56c583Sjmcneill }
4878c56c583Sjmcneill
488fddeb95fShamajima return ENXIO;
489fddeb95fShamajima }
490fddeb95fShamajima
491fddeb95fShamajima int
vraiu_get_props(void * self)492fddeb95fShamajima vraiu_get_props(void *self)
493fddeb95fShamajima {
494fddeb95fShamajima DPRINTFN(3, ("vraiu_get_props\n"));
495fddeb95fShamajima
496*df83eae3Sskrll return AUDIO_PROP_PLAYBACK;
497fddeb95fShamajima }
498fddeb95fShamajima
4998a962f23Sjmcneill void
vraiu_get_locks(void * self,kmutex_t ** intr,kmutex_t ** thread)5008a962f23Sjmcneill vraiu_get_locks(void *self, kmutex_t **intr, kmutex_t **thread)
5018a962f23Sjmcneill {
5028a962f23Sjmcneill struct vraiu_softc *sc;
5038a962f23Sjmcneill
5048a962f23Sjmcneill DPRINTFN(3, ("vraiu_get_locks\n"));
5058a962f23Sjmcneill sc = self;
5068a962f23Sjmcneill
5078a962f23Sjmcneill *intr = &sc->sc_intr_lock;
5088a962f23Sjmcneill *thread = &sc->sc_lock;
5098a962f23Sjmcneill }
5108a962f23Sjmcneill
511e622eac4Sisaki /* slinear16/mono -> ulinear10/mono with volume */
512fddeb95fShamajima static void
vraiu_slinear16_1(struct vraiu_softc * sc,u_short * dmap,void * p,int n)513fddeb95fShamajima vraiu_slinear16_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
514fddeb95fShamajima {
51593293b9eSkent short *q;
516fddeb95fShamajima
517fddeb95fShamajima DPRINTFN(3, ("vraiu_slinear16_1\n"));
51893293b9eSkent q = p;
519fddeb95fShamajima #ifdef DIAGNOSTIC
520fddeb95fShamajima if (n > AUDIO_BUF_SIZE) {
521fddeb95fShamajima printf("%s: output data too large (%d > %d)\n",
522cbab9cadSchs device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE);
523fddeb95fShamajima n = AUDIO_BUF_SIZE;
524fddeb95fShamajima }
525fddeb95fShamajima #endif
526fddeb95fShamajima n /= 2;
527fddeb95fShamajima while (n--) {
528e622eac4Sisaki int i = *q++;
529e622eac4Sisaki i = i * sc->sc_volume / 255;
530fddeb95fShamajima *dmap++ = (i >> 6) + 0x200;
531fddeb95fShamajima }
532fddeb95fShamajima }
533