bcm2835_vcaudio.c revision 1.3.2.2 1 1.3.2.2 yamt /* $NetBSD: bcm2835_vcaudio.c,v 1.3.2.2 2014/05/22 11:39:31 yamt Exp $ */
2 1.3.2.2 yamt
3 1.3.2.2 yamt /*-
4 1.3.2.2 yamt * Copyright (c) 2013 Jared D. McNeill <jmcneill (at) invisible.ca>
5 1.3.2.2 yamt * All rights reserved.
6 1.3.2.2 yamt *
7 1.3.2.2 yamt * Redistribution and use in source and binary forms, with or without
8 1.3.2.2 yamt * modification, are permitted provided that the following conditions
9 1.3.2.2 yamt * are met:
10 1.3.2.2 yamt * 1. Redistributions of source code must retain the above copyright
11 1.3.2.2 yamt * notice, this list of conditions and the following disclaimer.
12 1.3.2.2 yamt * 2. Redistributions in binary form must reproduce the above copyright
13 1.3.2.2 yamt * notice, this list of conditions and the following disclaimer in the
14 1.3.2.2 yamt * documentation and/or other materials provided with the distribution.
15 1.3.2.2 yamt *
16 1.3.2.2 yamt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.3.2.2 yamt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.3.2.2 yamt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.3.2.2 yamt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.3.2.2 yamt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.3.2.2 yamt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.3.2.2 yamt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.3.2.2 yamt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.3.2.2 yamt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.3.2.2 yamt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.3.2.2 yamt * POSSIBILITY OF SUCH DAMAGE.
27 1.3.2.2 yamt */
28 1.3.2.2 yamt
29 1.3.2.2 yamt /*
30 1.3.2.2 yamt * VideoCore audio interface
31 1.3.2.2 yamt */
32 1.3.2.2 yamt
33 1.3.2.2 yamt #include <sys/cdefs.h>
34 1.3.2.2 yamt __KERNEL_RCSID(0, "$NetBSD: bcm2835_vcaudio.c,v 1.3.2.2 2014/05/22 11:39:31 yamt Exp $");
35 1.3.2.2 yamt
36 1.3.2.2 yamt #include <sys/param.h>
37 1.3.2.2 yamt #include <sys/types.h>
38 1.3.2.2 yamt #include <sys/systm.h>
39 1.3.2.2 yamt #include <sys/device.h>
40 1.3.2.2 yamt #include <sys/conf.h>
41 1.3.2.2 yamt #include <sys/bus.h>
42 1.3.2.2 yamt #include <sys/kmem.h>
43 1.3.2.2 yamt #include <sys/workqueue.h>
44 1.3.2.2 yamt
45 1.3.2.2 yamt #include <sys/audioio.h>
46 1.3.2.2 yamt #include <dev/audio_if.h>
47 1.3.2.2 yamt #include <dev/auconv.h>
48 1.3.2.2 yamt
49 1.3.2.2 yamt #include <interface/compat/vchi_bsd.h>
50 1.3.2.2 yamt #include <interface/vchiq_arm/vchiq_netbsd.h>
51 1.3.2.2 yamt #include <interface/vchi/vchi.h>
52 1.3.2.2 yamt
53 1.3.2.2 yamt #include "bcm2835_vcaudioreg.h"
54 1.3.2.2 yamt
55 1.3.2.2 yamt #define vol2pct(vol) (((vol) * 100) / 255)
56 1.3.2.2 yamt
57 1.3.2.2 yamt enum {
58 1.3.2.2 yamt VCAUDIO_OUTPUT_CLASS,
59 1.3.2.2 yamt VCAUDIO_INPUT_CLASS,
60 1.3.2.2 yamt VCAUDIO_OUTPUT_MASTER_VOLUME,
61 1.3.2.2 yamt VCAUDIO_INPUT_DAC_VOLUME,
62 1.3.2.2 yamt VCAUDIO_ENUM_LAST,
63 1.3.2.2 yamt };
64 1.3.2.2 yamt
65 1.3.2.2 yamt enum vcaudio_dest {
66 1.3.2.2 yamt VCAUDIO_DEST_AUTO = 0,
67 1.3.2.2 yamt VCAUDIO_DEST_HP = 1,
68 1.3.2.2 yamt VCAUDIO_DEST_HDMI = 2,
69 1.3.2.2 yamt };
70 1.3.2.2 yamt
71 1.3.2.2 yamt struct vcaudio_work {
72 1.3.2.2 yamt struct work vw_wk;
73 1.3.2.2 yamt };
74 1.3.2.2 yamt
75 1.3.2.2 yamt struct vcaudio_softc {
76 1.3.2.2 yamt device_t sc_dev;
77 1.3.2.2 yamt device_t sc_audiodev;
78 1.3.2.2 yamt
79 1.3.2.2 yamt kmutex_t sc_lock;
80 1.3.2.2 yamt kmutex_t sc_intr_lock;
81 1.3.2.2 yamt
82 1.3.2.2 yamt kmutex_t sc_msglock;
83 1.3.2.2 yamt kcondvar_t sc_msgcv;
84 1.3.2.2 yamt
85 1.3.2.2 yamt struct audio_format sc_format;
86 1.3.2.2 yamt struct audio_encoding_set *sc_encodings;
87 1.3.2.2 yamt
88 1.3.2.2 yamt void (*sc_pint)(void *);
89 1.3.2.2 yamt void *sc_pintarg;
90 1.3.2.2 yamt audio_params_t sc_pparam;
91 1.3.2.2 yamt bool sc_started;
92 1.3.2.2 yamt int sc_pbytes;
93 1.3.2.2 yamt off_t sc_ppos;
94 1.3.2.2 yamt void *sc_pstart;
95 1.3.2.2 yamt void *sc_pend;
96 1.3.2.2 yamt int sc_pblksize;
97 1.3.2.2 yamt
98 1.3.2.2 yamt bool sc_msgdone;
99 1.3.2.2 yamt int sc_success;
100 1.3.2.2 yamt
101 1.3.2.2 yamt VCHI_INSTANCE_T sc_instance;
102 1.3.2.2 yamt VCHI_CONNECTION_T sc_connection;
103 1.3.2.2 yamt VCHI_SERVICE_HANDLE_T sc_service;
104 1.3.2.2 yamt
105 1.3.2.2 yamt struct workqueue *sc_wq;
106 1.3.2.2 yamt struct vcaudio_work sc_work;
107 1.3.2.2 yamt
108 1.3.2.2 yamt int sc_volume;
109 1.3.2.2 yamt enum vcaudio_dest sc_dest;
110 1.3.2.2 yamt };
111 1.3.2.2 yamt
112 1.3.2.2 yamt static int vcaudio_match(device_t, cfdata_t, void *);
113 1.3.2.2 yamt static void vcaudio_attach(device_t, device_t, void *);
114 1.3.2.2 yamt static int vcaudio_rescan(device_t, const char *, const int *);
115 1.3.2.2 yamt static void vcaudio_childdet(device_t, device_t);
116 1.3.2.2 yamt
117 1.3.2.2 yamt static int vcaudio_init(struct vcaudio_softc *);
118 1.3.2.2 yamt static void vcaudio_service_callback(void *,
119 1.3.2.2 yamt const VCHI_CALLBACK_REASON_T,
120 1.3.2.2 yamt void *);
121 1.3.2.2 yamt static int vcaudio_msg_sync(struct vcaudio_softc *, VC_AUDIO_MSG_T *, size_t);
122 1.3.2.2 yamt static void vcaudio_worker(struct work *, void *);
123 1.3.2.2 yamt
124 1.3.2.2 yamt static int vcaudio_open(void *, int);
125 1.3.2.2 yamt static void vcaudio_close(void *);
126 1.3.2.2 yamt static int vcaudio_query_encoding(void *, struct audio_encoding *);
127 1.3.2.2 yamt static int vcaudio_set_params(void *, int, int,
128 1.3.2.2 yamt audio_params_t *, audio_params_t *,
129 1.3.2.2 yamt stream_filter_list_t *,
130 1.3.2.2 yamt stream_filter_list_t *);
131 1.3.2.2 yamt static int vcaudio_halt_output(void *);
132 1.3.2.2 yamt static int vcaudio_halt_input(void *);
133 1.3.2.2 yamt static int vcaudio_set_port(void *, mixer_ctrl_t *);
134 1.3.2.2 yamt static int vcaudio_get_port(void *, mixer_ctrl_t *);
135 1.3.2.2 yamt static int vcaudio_query_devinfo(void *, mixer_devinfo_t *);
136 1.3.2.2 yamt static int vcaudio_getdev(void *, struct audio_device *);
137 1.3.2.2 yamt static int vcaudio_get_props(void *);
138 1.3.2.2 yamt static int vcaudio_round_blocksize(void *, int, int, const audio_params_t *);
139 1.3.2.2 yamt static size_t vcaudio_round_buffersize(void *, int, size_t);
140 1.3.2.2 yamt static int vcaudio_trigger_output(void *, void *, void *, int,
141 1.3.2.2 yamt void (*)(void *), void *,
142 1.3.2.2 yamt const audio_params_t *);
143 1.3.2.2 yamt static int vcaudio_trigger_input(void *, void *, void *, int,
144 1.3.2.2 yamt void (*)(void *), void *,
145 1.3.2.2 yamt const audio_params_t *);
146 1.3.2.2 yamt static void vcaudio_get_locks(void *, kmutex_t **, kmutex_t **);
147 1.3.2.2 yamt
148 1.3.2.2 yamt static const struct audio_hw_if vcaudio_hw_if = {
149 1.3.2.2 yamt .open = vcaudio_open,
150 1.3.2.2 yamt .close = vcaudio_close,
151 1.3.2.2 yamt .query_encoding = vcaudio_query_encoding,
152 1.3.2.2 yamt .set_params = vcaudio_set_params,
153 1.3.2.2 yamt .halt_output = vcaudio_halt_output,
154 1.3.2.2 yamt .halt_input = vcaudio_halt_input,
155 1.3.2.2 yamt .getdev = vcaudio_getdev,
156 1.3.2.2 yamt .set_port = vcaudio_set_port,
157 1.3.2.2 yamt .get_port = vcaudio_get_port,
158 1.3.2.2 yamt .query_devinfo = vcaudio_query_devinfo,
159 1.3.2.2 yamt .get_props = vcaudio_get_props,
160 1.3.2.2 yamt .round_blocksize = vcaudio_round_blocksize,
161 1.3.2.2 yamt .round_buffersize = vcaudio_round_buffersize,
162 1.3.2.2 yamt .trigger_output = vcaudio_trigger_output,
163 1.3.2.2 yamt .trigger_input = vcaudio_trigger_input,
164 1.3.2.2 yamt .get_locks = vcaudio_get_locks,
165 1.3.2.2 yamt };
166 1.3.2.2 yamt
167 1.3.2.2 yamt CFATTACH_DECL2_NEW(vcaudio, sizeof(struct vcaudio_softc),
168 1.3.2.2 yamt vcaudio_match, vcaudio_attach, NULL, NULL, vcaudio_rescan, vcaudio_childdet);
169 1.3.2.2 yamt
170 1.3.2.2 yamt static int
171 1.3.2.2 yamt vcaudio_match(device_t parent, cfdata_t match, void *aux)
172 1.3.2.2 yamt {
173 1.3.2.2 yamt struct vchiq_attach_args *vaa = aux;
174 1.3.2.2 yamt
175 1.3.2.2 yamt return !strcmp(vaa->vaa_name, "AUDS");
176 1.3.2.2 yamt }
177 1.3.2.2 yamt
178 1.3.2.2 yamt static void
179 1.3.2.2 yamt vcaudio_attach(device_t parent, device_t self, void *aux)
180 1.3.2.2 yamt {
181 1.3.2.2 yamt struct vcaudio_softc *sc = device_private(self);
182 1.3.2.2 yamt int error;
183 1.3.2.2 yamt
184 1.3.2.2 yamt sc->sc_dev = self;
185 1.3.2.2 yamt mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
186 1.3.2.2 yamt mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
187 1.3.2.2 yamt mutex_init(&sc->sc_msglock, MUTEX_DEFAULT, IPL_NONE);
188 1.3.2.2 yamt cv_init(&sc->sc_msgcv, "vcaudiocv");
189 1.3.2.2 yamt sc->sc_success = -1;
190 1.3.2.2 yamt error = workqueue_create(&sc->sc_wq, "vcaudiowq", vcaudio_worker,
191 1.3.2.2 yamt sc, PRI_BIO, IPL_SCHED, WQ_MPSAFE);
192 1.3.2.2 yamt if (error) {
193 1.3.2.2 yamt aprint_error(": couldn't create workqueue (%d)\n", error);
194 1.3.2.2 yamt return;
195 1.3.2.2 yamt }
196 1.3.2.2 yamt
197 1.3.2.2 yamt aprint_naive("\n");
198 1.3.2.2 yamt aprint_normal(": AUDS\n");
199 1.3.2.2 yamt
200 1.3.2.2 yamt if (vcaudio_init(sc) != 0) {
201 1.3.2.2 yamt aprint_error_dev(self, "not configured\n");
202 1.3.2.2 yamt return;
203 1.3.2.2 yamt }
204 1.3.2.2 yamt
205 1.3.2.2 yamt vcaudio_rescan(self, NULL, NULL);
206 1.3.2.2 yamt }
207 1.3.2.2 yamt
208 1.3.2.2 yamt static int
209 1.3.2.2 yamt vcaudio_rescan(device_t self, const char *ifattr, const int *locs)
210 1.3.2.2 yamt {
211 1.3.2.2 yamt struct vcaudio_softc *sc = device_private(self);
212 1.3.2.2 yamt
213 1.3.2.2 yamt if (ifattr_match(ifattr, "audiobus") && sc->sc_audiodev == NULL) {
214 1.3.2.2 yamt sc->sc_audiodev = audio_attach_mi(&vcaudio_hw_if,
215 1.3.2.2 yamt sc, sc->sc_dev);
216 1.3.2.2 yamt }
217 1.3.2.2 yamt return 0;
218 1.3.2.2 yamt }
219 1.3.2.2 yamt
220 1.3.2.2 yamt static void
221 1.3.2.2 yamt vcaudio_childdet(device_t self, device_t child)
222 1.3.2.2 yamt {
223 1.3.2.2 yamt struct vcaudio_softc *sc = device_private(self);
224 1.3.2.2 yamt
225 1.3.2.2 yamt if (sc->sc_audiodev == child)
226 1.3.2.2 yamt sc->sc_audiodev = NULL;
227 1.3.2.2 yamt }
228 1.3.2.2 yamt
229 1.3.2.2 yamt static int
230 1.3.2.2 yamt vcaudio_init(struct vcaudio_softc *sc)
231 1.3.2.2 yamt {
232 1.3.2.2 yamt VC_AUDIO_MSG_T msg;
233 1.3.2.2 yamt int error;
234 1.3.2.2 yamt
235 1.3.2.2 yamt sc->sc_volume = 128;
236 1.3.2.2 yamt sc->sc_dest = VCAUDIO_DEST_AUTO;
237 1.3.2.2 yamt
238 1.3.2.2 yamt sc->sc_format.mode = AUMODE_PLAY|AUMODE_RECORD;
239 1.3.2.2 yamt sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_LE;
240 1.3.2.2 yamt sc->sc_format.validbits = 16;
241 1.3.2.2 yamt sc->sc_format.precision = 16;
242 1.3.2.2 yamt sc->sc_format.channels = 2;
243 1.3.2.2 yamt sc->sc_format.channel_mask = AUFMT_STEREO;
244 1.3.2.2 yamt sc->sc_format.frequency_type = 0;
245 1.3.2.2 yamt sc->sc_format.frequency[0] = 8000;
246 1.3.2.2 yamt sc->sc_format.frequency[1] = 48000;
247 1.3.2.2 yamt
248 1.3.2.2 yamt error = auconv_create_encodings(&sc->sc_format, 1, &sc->sc_encodings);
249 1.3.2.2 yamt if (error) {
250 1.3.2.2 yamt aprint_error_dev(sc->sc_dev,
251 1.3.2.2 yamt "couldn't create encodings (error=%d)\n", error);
252 1.3.2.2 yamt return error;
253 1.3.2.2 yamt }
254 1.3.2.2 yamt
255 1.3.2.2 yamt error = vchi_initialise(&sc->sc_instance);
256 1.3.2.2 yamt if (error) {
257 1.3.2.2 yamt device_printf(sc->sc_dev, "couldn't init vchi instance (%d)\n",
258 1.3.2.2 yamt error);
259 1.3.2.2 yamt return EIO;
260 1.3.2.2 yamt }
261 1.3.2.2 yamt
262 1.3.2.2 yamt error = vchi_connect(NULL, 0, sc->sc_instance);
263 1.3.2.2 yamt if (error) {
264 1.3.2.2 yamt device_printf(sc->sc_dev, "couldn't connect vchi (%d)\n",
265 1.3.2.2 yamt error);
266 1.3.2.2 yamt return EIO;
267 1.3.2.2 yamt }
268 1.3.2.2 yamt
269 1.3.2.2 yamt SERVICE_CREATION_T setup = {
270 1.3.2.2 yamt .version = VCHI_VERSION(VC_AUDIOSERV_VER),
271 1.3.2.2 yamt .service_id = VC_AUDIO_SERVER_NAME,
272 1.3.2.2 yamt .connection = &sc->sc_connection,
273 1.3.2.2 yamt .rx_fifo_size = 0,
274 1.3.2.2 yamt .tx_fifo_size = 0,
275 1.3.2.2 yamt .callback = vcaudio_service_callback,
276 1.3.2.2 yamt .callback_param = sc,
277 1.3.2.2 yamt .want_unaligned_bulk_rx = 1,
278 1.3.2.2 yamt .want_unaligned_bulk_tx = 1,
279 1.3.2.2 yamt .want_crc = 0,
280 1.3.2.2 yamt };
281 1.3.2.2 yamt
282 1.3.2.2 yamt error = vchi_service_open(sc->sc_instance, &setup, &sc->sc_service);
283 1.3.2.2 yamt if (error) {
284 1.3.2.2 yamt device_printf(sc->sc_dev, "couldn't open service (%d)\n",
285 1.3.2.2 yamt error);
286 1.3.2.2 yamt return EIO;
287 1.3.2.2 yamt }
288 1.3.2.2 yamt vchi_service_release(sc->sc_service);
289 1.3.2.2 yamt
290 1.3.2.2 yamt vchi_service_use(sc->sc_service);
291 1.3.2.2 yamt memset(&msg, 0, sizeof(msg));
292 1.3.2.2 yamt msg.type = VC_AUDIO_MSG_TYPE_OPEN;
293 1.3.2.2 yamt error = vchi_msg_queue(sc->sc_service, &msg, sizeof(msg),
294 1.3.2.2 yamt VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
295 1.3.2.2 yamt if (error) {
296 1.3.2.2 yamt device_printf(sc->sc_dev, "couldn't send OPEN message (%d)\n",
297 1.3.2.2 yamt error);
298 1.3.2.2 yamt }
299 1.3.2.2 yamt
300 1.3.2.2 yamt memset(&msg, 0, sizeof(msg));
301 1.3.2.2 yamt msg.type = VC_AUDIO_MSG_TYPE_CONTROL;
302 1.3.2.2 yamt msg.u.control.volume = vol2pct(sc->sc_volume);
303 1.3.2.2 yamt msg.u.control.dest = VCAUDIO_DEST_AUTO;
304 1.3.2.2 yamt error = vcaudio_msg_sync(sc, &msg, sizeof(msg));
305 1.3.2.2 yamt if (error) {
306 1.3.2.2 yamt device_printf(sc->sc_dev, "couldn't send CONTROL message (%d)\n", error);
307 1.3.2.2 yamt }
308 1.3.2.2 yamt vchi_service_release(sc->sc_service);
309 1.3.2.2 yamt
310 1.3.2.2 yamt return 0;
311 1.3.2.2 yamt }
312 1.3.2.2 yamt
313 1.3.2.2 yamt static void
314 1.3.2.2 yamt vcaudio_service_callback(void *priv, const VCHI_CALLBACK_REASON_T reason,
315 1.3.2.2 yamt void *msg_handle)
316 1.3.2.2 yamt {
317 1.3.2.2 yamt struct vcaudio_softc *sc = priv;
318 1.3.2.2 yamt VC_AUDIO_MSG_T msg;
319 1.3.2.2 yamt int32_t msglen = 0;
320 1.3.2.2 yamt int error;
321 1.3.2.2 yamt void (*intr)(void *) = NULL;
322 1.3.2.2 yamt void *intrarg = NULL;
323 1.3.2.2 yamt
324 1.3.2.2 yamt if (sc == NULL || reason != VCHI_CALLBACK_MSG_AVAILABLE)
325 1.3.2.2 yamt return;
326 1.3.2.2 yamt
327 1.3.2.2 yamt memset(&msg, 0, sizeof(msg));
328 1.3.2.2 yamt error = vchi_msg_dequeue(sc->sc_service, &msg, sizeof(msg), &msglen,
329 1.3.2.2 yamt VCHI_FLAGS_NONE);
330 1.3.2.2 yamt if (error) {
331 1.3.2.2 yamt device_printf(sc->sc_dev, "couldn't dequeue msg (%d)\n",
332 1.3.2.2 yamt error);
333 1.3.2.2 yamt return;
334 1.3.2.2 yamt }
335 1.3.2.2 yamt
336 1.3.2.2 yamt switch (msg.type) {
337 1.3.2.2 yamt case VC_AUDIO_MSG_TYPE_RESULT:
338 1.3.2.2 yamt mutex_enter(&sc->sc_msglock);
339 1.3.2.2 yamt sc->sc_success = msg.u.result.success;
340 1.3.2.2 yamt sc->sc_msgdone = true;
341 1.3.2.2 yamt cv_broadcast(&sc->sc_msgcv);
342 1.3.2.2 yamt mutex_exit(&sc->sc_msglock);
343 1.3.2.2 yamt break;
344 1.3.2.2 yamt case VC_AUDIO_MSG_TYPE_COMPLETE:
345 1.3.2.2 yamt intr = msg.u.complete.callback;
346 1.3.2.2 yamt intrarg = msg.u.complete.cookie;
347 1.3.2.2 yamt if (intr && intrarg) {
348 1.3.2.2 yamt mutex_enter(&sc->sc_intr_lock);
349 1.3.2.2 yamt if (msg.u.complete.count > 0 && msg.u.complete.count <= sc->sc_pblksize) {
350 1.3.2.2 yamt sc->sc_pbytes += msg.u.complete.count;
351 1.3.2.2 yamt } else {
352 1.3.2.2 yamt if (sc->sc_started) {
353 1.3.2.2 yamt device_printf(sc->sc_dev, "WARNING: count = %d\n", msg.u.complete.count);
354 1.3.2.2 yamt }
355 1.3.2.2 yamt }
356 1.3.2.2 yamt if (sc->sc_pbytes >= sc->sc_pblksize) {
357 1.3.2.2 yamt sc->sc_pbytes -= sc->sc_pblksize;
358 1.3.2.2 yamt intr(intrarg);
359 1.3.2.2 yamt workqueue_enqueue(sc->sc_wq, (struct work *)&sc->sc_work, NULL);
360 1.3.2.2 yamt }
361 1.3.2.2 yamt mutex_exit(&sc->sc_intr_lock);
362 1.3.2.2 yamt }
363 1.3.2.2 yamt break;
364 1.3.2.2 yamt default:
365 1.3.2.2 yamt break;
366 1.3.2.2 yamt }
367 1.3.2.2 yamt }
368 1.3.2.2 yamt
369 1.3.2.2 yamt static void
370 1.3.2.2 yamt vcaudio_worker(struct work *wk, void *priv)
371 1.3.2.2 yamt {
372 1.3.2.2 yamt struct vcaudio_softc *sc = priv;
373 1.3.2.2 yamt VC_AUDIO_MSG_T msg;
374 1.3.2.2 yamt void (*intr)(void *);
375 1.3.2.2 yamt void *intrarg;
376 1.3.2.2 yamt void *block;
377 1.3.2.2 yamt int error, resid, off, nb, count;
378 1.3.2.2 yamt
379 1.3.2.2 yamt mutex_enter(&sc->sc_intr_lock);
380 1.3.2.2 yamt intr = sc->sc_pint;
381 1.3.2.2 yamt intrarg = sc->sc_pintarg;
382 1.3.2.2 yamt
383 1.3.2.2 yamt if (intr == NULL || intrarg == NULL) {
384 1.3.2.2 yamt mutex_exit(&sc->sc_intr_lock);
385 1.3.2.2 yamt return;
386 1.3.2.2 yamt }
387 1.3.2.2 yamt
388 1.3.2.2 yamt vchi_service_use(sc->sc_service);
389 1.3.2.2 yamt
390 1.3.2.2 yamt if (sc->sc_started == false) {
391 1.3.2.2 yamt #ifdef VCAUDIO_DEBUG
392 1.3.2.2 yamt device_printf(sc->sc_dev, "starting output\n");
393 1.3.2.2 yamt #endif
394 1.3.2.2 yamt
395 1.3.2.2 yamt memset(&msg, 0, sizeof(msg));
396 1.3.2.2 yamt msg.type = VC_AUDIO_MSG_TYPE_CONFIG;
397 1.3.2.2 yamt msg.u.config.channels = sc->sc_pparam.channels;
398 1.3.2.2 yamt msg.u.config.samplerate = sc->sc_pparam.sample_rate;
399 1.3.2.2 yamt msg.u.config.bps = sc->sc_pparam.precision;
400 1.3.2.2 yamt error = vcaudio_msg_sync(sc, &msg, sizeof(msg));
401 1.3.2.2 yamt if (error) {
402 1.3.2.2 yamt printf("%s: failed to config (%d)\n", __func__, error);
403 1.3.2.2 yamt goto done;
404 1.3.2.2 yamt }
405 1.3.2.2 yamt
406 1.3.2.2 yamt memset(&msg, 0, sizeof(msg));
407 1.3.2.2 yamt msg.type = VC_AUDIO_MSG_TYPE_START;
408 1.3.2.2 yamt error = vchi_msg_queue(sc->sc_service, &msg, sizeof(msg),
409 1.3.2.2 yamt VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
410 1.3.2.2 yamt if (error) {
411 1.3.2.2 yamt printf("%s: failed to start (%d)\n", __func__, error);
412 1.3.2.2 yamt goto done;
413 1.3.2.2 yamt }
414 1.3.2.2 yamt
415 1.3.2.2 yamt sc->sc_started = true;
416 1.3.2.2 yamt sc->sc_pbytes = 0;
417 1.3.2.2 yamt sc->sc_ppos = 0;
418 1.3.2.2 yamt sc->sc_pblksize = sc->sc_pblksize;
419 1.3.2.2 yamt count = (uintptr_t)sc->sc_pend - (uintptr_t)sc->sc_pstart;
420 1.3.2.2 yamt
421 1.3.2.2 yamt /* initial silence */
422 1.3.2.2 yamt memset(&msg, 0, sizeof(msg));
423 1.3.2.2 yamt msg.type = VC_AUDIO_MSG_TYPE_WRITE;
424 1.3.2.2 yamt msg.u.write.count = PAGE_SIZE * 3;
425 1.3.2.2 yamt msg.u.write.callback = NULL;
426 1.3.2.2 yamt msg.u.write.cookie = NULL;
427 1.3.2.2 yamt msg.u.write.silence = 1;
428 1.3.2.2 yamt msg.u.write.max_packet = 0;
429 1.3.2.2 yamt error = vchi_msg_queue(sc->sc_service, &msg, sizeof(msg),
430 1.3.2.2 yamt VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
431 1.3.2.2 yamt if (error) {
432 1.3.2.2 yamt printf("%s: failed to write (%d)\n", __func__, error);
433 1.3.2.2 yamt goto done;
434 1.3.2.2 yamt }
435 1.3.2.2 yamt } else {
436 1.3.2.2 yamt count = sc->sc_pblksize;
437 1.3.2.2 yamt }
438 1.3.2.2 yamt
439 1.3.2.2 yamt memset(&msg, 0, sizeof(msg));
440 1.3.2.2 yamt msg.type = VC_AUDIO_MSG_TYPE_WRITE;
441 1.3.2.2 yamt msg.u.write.max_packet = 4000;
442 1.3.2.2 yamt msg.u.write.count = count;
443 1.3.2.2 yamt msg.u.write.callback = intr;
444 1.3.2.2 yamt msg.u.write.cookie = intrarg;
445 1.3.2.2 yamt msg.u.write.silence = 0;
446 1.3.2.2 yamt
447 1.3.2.2 yamt error = vchi_msg_queue(sc->sc_service, &msg, sizeof(msg),
448 1.3.2.2 yamt VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
449 1.3.2.2 yamt if (error) {
450 1.3.2.2 yamt printf("%s: failed to write (%d)\n", __func__, error);
451 1.3.2.2 yamt goto done;
452 1.3.2.2 yamt }
453 1.3.2.2 yamt
454 1.3.2.2 yamt block = (uint8_t *)sc->sc_pstart + sc->sc_ppos;
455 1.3.2.2 yamt resid = count;
456 1.3.2.2 yamt off = 0;
457 1.3.2.2 yamt while (resid > 0) {
458 1.3.2.2 yamt nb = min(resid, msg.u.write.max_packet);
459 1.3.2.2 yamt error = vchi_msg_queue(sc->sc_service,
460 1.3.2.2 yamt (char *)block + off, nb,
461 1.3.2.2 yamt VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
462 1.3.2.2 yamt if (error) {
463 1.3.2.2 yamt printf("%s: failed to queue data (%d)\n", __func__, error);
464 1.3.2.2 yamt goto done;
465 1.3.2.2 yamt }
466 1.3.2.2 yamt off += nb;
467 1.3.2.2 yamt resid -= nb;
468 1.3.2.2 yamt }
469 1.3.2.2 yamt
470 1.3.2.2 yamt sc->sc_ppos += count;
471 1.3.2.2 yamt if ((uint8_t *)sc->sc_pstart + sc->sc_ppos >= (uint8_t *)sc->sc_pend)
472 1.3.2.2 yamt sc->sc_ppos = 0;
473 1.3.2.2 yamt
474 1.3.2.2 yamt done:
475 1.3.2.2 yamt mutex_exit(&sc->sc_intr_lock);
476 1.3.2.2 yamt vchi_service_release(sc->sc_service);
477 1.3.2.2 yamt }
478 1.3.2.2 yamt
479 1.3.2.2 yamt static int
480 1.3.2.2 yamt vcaudio_msg_sync(struct vcaudio_softc *sc, VC_AUDIO_MSG_T *msg, size_t msglen)
481 1.3.2.2 yamt {
482 1.3.2.2 yamt int error = 0;
483 1.3.2.2 yamt
484 1.3.2.2 yamt mutex_enter(&sc->sc_msglock);
485 1.3.2.2 yamt
486 1.3.2.2 yamt sc->sc_success = -1;
487 1.3.2.2 yamt sc->sc_msgdone = false;
488 1.3.2.2 yamt
489 1.3.2.2 yamt error = vchi_msg_queue(sc->sc_service, msg, msglen,
490 1.3.2.2 yamt VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
491 1.3.2.2 yamt if (error) {
492 1.3.2.2 yamt printf("%s: failed to queue message (%d)\n", __func__, error);
493 1.3.2.2 yamt goto done;
494 1.3.2.2 yamt }
495 1.3.2.2 yamt
496 1.3.2.2 yamt while (!sc->sc_msgdone) {
497 1.3.2.2 yamt error = cv_wait_sig(&sc->sc_msgcv, &sc->sc_msglock);
498 1.3.2.2 yamt if (error)
499 1.3.2.2 yamt break;
500 1.3.2.2 yamt }
501 1.3.2.2 yamt if (sc->sc_success != 0)
502 1.3.2.2 yamt error = EIO;
503 1.3.2.2 yamt done:
504 1.3.2.2 yamt mutex_exit(&sc->sc_msglock);
505 1.3.2.2 yamt
506 1.3.2.2 yamt return error;
507 1.3.2.2 yamt }
508 1.3.2.2 yamt
509 1.3.2.2 yamt static int
510 1.3.2.2 yamt vcaudio_open(void *priv, int flags)
511 1.3.2.2 yamt {
512 1.3.2.2 yamt return 0;
513 1.3.2.2 yamt }
514 1.3.2.2 yamt
515 1.3.2.2 yamt static void
516 1.3.2.2 yamt vcaudio_close(void *priv)
517 1.3.2.2 yamt {
518 1.3.2.2 yamt }
519 1.3.2.2 yamt
520 1.3.2.2 yamt static int
521 1.3.2.2 yamt vcaudio_query_encoding(void *priv, struct audio_encoding *ae)
522 1.3.2.2 yamt {
523 1.3.2.2 yamt struct vcaudio_softc *sc = priv;
524 1.3.2.2 yamt
525 1.3.2.2 yamt return auconv_query_encoding(sc->sc_encodings, ae);
526 1.3.2.2 yamt }
527 1.3.2.2 yamt
528 1.3.2.2 yamt static int
529 1.3.2.2 yamt vcaudio_set_params(void *priv, int setmode, int usemode,
530 1.3.2.2 yamt audio_params_t *play, audio_params_t *rec,
531 1.3.2.2 yamt stream_filter_list_t *pfil, stream_filter_list_t *rfil)
532 1.3.2.2 yamt {
533 1.3.2.2 yamt struct vcaudio_softc *sc = priv;
534 1.3.2.2 yamt int index;
535 1.3.2.2 yamt
536 1.3.2.2 yamt if (play && (setmode & AUMODE_PLAY)) {
537 1.3.2.2 yamt index = auconv_set_converter(&sc->sc_format, 1,
538 1.3.2.2 yamt AUMODE_PLAY, play, true, pfil);
539 1.3.2.2 yamt if (index < 0)
540 1.3.2.2 yamt return EINVAL;
541 1.3.2.2 yamt }
542 1.3.2.2 yamt
543 1.3.2.2 yamt return 0;
544 1.3.2.2 yamt }
545 1.3.2.2 yamt
546 1.3.2.2 yamt static int
547 1.3.2.2 yamt vcaudio_halt_output(void *priv)
548 1.3.2.2 yamt {
549 1.3.2.2 yamt struct vcaudio_softc *sc = priv;
550 1.3.2.2 yamt VC_AUDIO_MSG_T msg;
551 1.3.2.2 yamt int error = 0;
552 1.3.2.2 yamt
553 1.3.2.2 yamt vchi_service_use(sc->sc_service);
554 1.3.2.2 yamt memset(&msg, 0, sizeof(msg));
555 1.3.2.2 yamt msg.type = VC_AUDIO_MSG_TYPE_STOP;
556 1.3.2.2 yamt msg.u.stop.draining = 1;
557 1.3.2.2 yamt error = vchi_msg_queue(sc->sc_service, &msg, sizeof(msg),
558 1.3.2.2 yamt VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
559 1.3.2.2 yamt if (error) {
560 1.3.2.2 yamt device_printf(sc->sc_dev, "couldn't send STOP message (%d)\n",
561 1.3.2.2 yamt error);
562 1.3.2.2 yamt }
563 1.3.2.2 yamt vchi_service_release(sc->sc_service);
564 1.3.2.2 yamt
565 1.3.2.2 yamt sc->sc_pint = NULL;
566 1.3.2.2 yamt sc->sc_pintarg = NULL;
567 1.3.2.2 yamt sc->sc_started = false;
568 1.3.2.2 yamt
569 1.3.2.2 yamt #ifdef VCAUDIO_DEBUG
570 1.3.2.2 yamt device_printf(sc->sc_dev, "halting output\n");
571 1.3.2.2 yamt #endif
572 1.3.2.2 yamt
573 1.3.2.2 yamt return error;
574 1.3.2.2 yamt }
575 1.3.2.2 yamt
576 1.3.2.2 yamt static int
577 1.3.2.2 yamt vcaudio_halt_input(void *priv)
578 1.3.2.2 yamt {
579 1.3.2.2 yamt return EINVAL;
580 1.3.2.2 yamt }
581 1.3.2.2 yamt
582 1.3.2.2 yamt static int
583 1.3.2.2 yamt vcaudio_set_port(void *priv, mixer_ctrl_t *mc)
584 1.3.2.2 yamt {
585 1.3.2.2 yamt struct vcaudio_softc *sc = priv;
586 1.3.2.2 yamt VC_AUDIO_MSG_T msg;
587 1.3.2.2 yamt int error;
588 1.3.2.2 yamt
589 1.3.2.2 yamt switch (mc->dev) {
590 1.3.2.2 yamt case VCAUDIO_OUTPUT_MASTER_VOLUME:
591 1.3.2.2 yamt case VCAUDIO_INPUT_DAC_VOLUME:
592 1.3.2.2 yamt sc->sc_volume = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
593 1.3.2.2 yamt memset(&msg, 0, sizeof(msg));
594 1.3.2.2 yamt msg.type = VC_AUDIO_MSG_TYPE_CONTROL;
595 1.3.2.2 yamt msg.u.control.volume = vol2pct(sc->sc_volume);
596 1.3.2.2 yamt msg.u.control.dest = VCAUDIO_DEST_AUTO;
597 1.3.2.2 yamt vchi_service_use(sc->sc_service);
598 1.3.2.2 yamt error = vcaudio_msg_sync(sc, &msg, sizeof(msg));
599 1.3.2.2 yamt if (error) {
600 1.3.2.2 yamt device_printf(sc->sc_dev, "couldn't send CONTROL message (%d)\n", error);
601 1.3.2.2 yamt }
602 1.3.2.2 yamt vchi_service_release(sc->sc_service);
603 1.3.2.2 yamt
604 1.3.2.2 yamt return error;
605 1.3.2.2 yamt }
606 1.3.2.2 yamt return ENXIO;
607 1.3.2.2 yamt }
608 1.3.2.2 yamt
609 1.3.2.2 yamt static int
610 1.3.2.2 yamt vcaudio_get_port(void *priv, mixer_ctrl_t *mc)
611 1.3.2.2 yamt {
612 1.3.2.2 yamt struct vcaudio_softc *sc = priv;
613 1.3.2.2 yamt
614 1.3.2.2 yamt switch (mc->dev) {
615 1.3.2.2 yamt case VCAUDIO_OUTPUT_MASTER_VOLUME:
616 1.3.2.2 yamt case VCAUDIO_INPUT_DAC_VOLUME:
617 1.3.2.2 yamt mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
618 1.3.2.2 yamt mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
619 1.3.2.2 yamt sc->sc_volume;
620 1.3.2.2 yamt return 0;
621 1.3.2.2 yamt }
622 1.3.2.2 yamt return ENXIO;
623 1.3.2.2 yamt }
624 1.3.2.2 yamt
625 1.3.2.2 yamt static int
626 1.3.2.2 yamt vcaudio_query_devinfo(void *priv, mixer_devinfo_t *di)
627 1.3.2.2 yamt {
628 1.3.2.2 yamt switch (di->index) {
629 1.3.2.2 yamt case VCAUDIO_OUTPUT_CLASS:
630 1.3.2.2 yamt di->mixer_class = VCAUDIO_OUTPUT_CLASS;
631 1.3.2.2 yamt strcpy(di->label.name, AudioCoutputs);
632 1.3.2.2 yamt di->type = AUDIO_MIXER_CLASS;
633 1.3.2.2 yamt di->next = di->prev = AUDIO_MIXER_LAST;
634 1.3.2.2 yamt return 0;
635 1.3.2.2 yamt case VCAUDIO_INPUT_CLASS:
636 1.3.2.2 yamt di->mixer_class = VCAUDIO_INPUT_CLASS;
637 1.3.2.2 yamt strcpy(di->label.name, AudioCinputs);
638 1.3.2.2 yamt di->type = AUDIO_MIXER_CLASS;
639 1.3.2.2 yamt di->next = di->prev = AUDIO_MIXER_LAST;
640 1.3.2.2 yamt return 0;
641 1.3.2.2 yamt case VCAUDIO_OUTPUT_MASTER_VOLUME:
642 1.3.2.2 yamt di->mixer_class = VCAUDIO_OUTPUT_CLASS;
643 1.3.2.2 yamt strcpy(di->label.name, AudioNmaster);
644 1.3.2.2 yamt di->type = AUDIO_MIXER_VALUE;
645 1.3.2.2 yamt di->next = di->prev = AUDIO_MIXER_LAST;
646 1.3.2.2 yamt di->un.v.num_channels = 2;
647 1.3.2.2 yamt strcpy(di->un.v.units.name, AudioNvolume);
648 1.3.2.2 yamt return 0;
649 1.3.2.2 yamt case VCAUDIO_INPUT_DAC_VOLUME:
650 1.3.2.2 yamt di->mixer_class = VCAUDIO_INPUT_CLASS;
651 1.3.2.2 yamt strcpy(di->label.name, AudioNdac);
652 1.3.2.2 yamt di->type = AUDIO_MIXER_VALUE;
653 1.3.2.2 yamt di->next = di->prev = AUDIO_MIXER_LAST;
654 1.3.2.2 yamt di->un.v.num_channels = 2;
655 1.3.2.2 yamt strcpy(di->un.v.units.name, AudioNvolume);
656 1.3.2.2 yamt return 0;
657 1.3.2.2 yamt }
658 1.3.2.2 yamt
659 1.3.2.2 yamt return ENXIO;
660 1.3.2.2 yamt }
661 1.3.2.2 yamt
662 1.3.2.2 yamt static int
663 1.3.2.2 yamt vcaudio_getdev(void *priv, struct audio_device *audiodev)
664 1.3.2.2 yamt {
665 1.3.2.2 yamt snprintf(audiodev->name, sizeof(audiodev->name), "VCHIQ AUDS");
666 1.3.2.2 yamt snprintf(audiodev->version, sizeof(audiodev->version), "");
667 1.3.2.2 yamt snprintf(audiodev->config, sizeof(audiodev->config), "vcaudio");
668 1.3.2.2 yamt return 0;
669 1.3.2.2 yamt }
670 1.3.2.2 yamt
671 1.3.2.2 yamt static int
672 1.3.2.2 yamt vcaudio_get_props(void *priv)
673 1.3.2.2 yamt {
674 1.3.2.2 yamt return AUDIO_PROP_PLAYBACK|AUDIO_PROP_CAPTURE|AUDIO_PROP_INDEPENDENT;
675 1.3.2.2 yamt }
676 1.3.2.2 yamt
677 1.3.2.2 yamt static int
678 1.3.2.2 yamt vcaudio_round_blocksize(void *priv, int bs, int mode,
679 1.3.2.2 yamt const audio_params_t *params)
680 1.3.2.2 yamt {
681 1.3.2.2 yamt return PAGE_SIZE;
682 1.3.2.2 yamt }
683 1.3.2.2 yamt
684 1.3.2.2 yamt static size_t
685 1.3.2.2 yamt vcaudio_round_buffersize(void *priv, int direction, size_t bufsize)
686 1.3.2.2 yamt {
687 1.3.2.2 yamt size_t sz;
688 1.3.2.2 yamt
689 1.3.2.2 yamt sz = (bufsize + 0x3ff) & ~0x3ff;
690 1.3.2.2 yamt if (sz > 32768)
691 1.3.2.2 yamt sz = 32768;
692 1.3.2.2 yamt
693 1.3.2.2 yamt return sz;
694 1.3.2.2 yamt }
695 1.3.2.2 yamt
696 1.3.2.2 yamt static int
697 1.3.2.2 yamt vcaudio_trigger_output(void *priv, void *start, void *end, int blksize,
698 1.3.2.2 yamt void (*intr)(void *), void *intrarg, const audio_params_t *params)
699 1.3.2.2 yamt {
700 1.3.2.2 yamt struct vcaudio_softc *sc = priv;
701 1.3.2.2 yamt
702 1.3.2.2 yamt sc->sc_pparam = *params;
703 1.3.2.2 yamt sc->sc_pint = intr;
704 1.3.2.2 yamt sc->sc_pintarg = intrarg;
705 1.3.2.2 yamt sc->sc_ppos = 0;
706 1.3.2.2 yamt sc->sc_pstart = start;
707 1.3.2.2 yamt sc->sc_pend = end;
708 1.3.2.2 yamt sc->sc_pblksize = blksize;
709 1.3.2.2 yamt workqueue_enqueue(sc->sc_wq, (struct work *)&sc->sc_work, NULL);
710 1.3.2.2 yamt
711 1.3.2.2 yamt return 0;
712 1.3.2.2 yamt }
713 1.3.2.2 yamt
714 1.3.2.2 yamt static int
715 1.3.2.2 yamt vcaudio_trigger_input(void *priv, void *start, void *end, int blksize,
716 1.3.2.2 yamt void (*intr)(void *), void *intrarg, const audio_params_t *params)
717 1.3.2.2 yamt {
718 1.3.2.2 yamt return EINVAL;
719 1.3.2.2 yamt }
720 1.3.2.2 yamt
721 1.3.2.2 yamt static void
722 1.3.2.2 yamt vcaudio_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread)
723 1.3.2.2 yamt {
724 1.3.2.2 yamt struct vcaudio_softc *sc = priv;
725 1.3.2.2 yamt
726 1.3.2.2 yamt *intr = &sc->sc_intr_lock;
727 1.3.2.2 yamt *thread = &sc->sc_lock;
728 1.3.2.2 yamt }
729