This source file includes following definitions.
- bcm2835_audio_lock
- bcm2835_audio_unlock
- bcm2835_audio_send_msg_locked
- bcm2835_audio_send_msg
- bcm2835_audio_send_simple
- audio_vchi_callback
- vc_vchi_audio_init
- vc_vchi_audio_deinit
- bcm2835_new_vchi_ctx
- bcm2835_free_vchi_ctx
- bcm2835_audio_open
- bcm2835_audio_set_ctls
- bcm2835_audio_set_params
- bcm2835_audio_start
- bcm2835_audio_stop
- bcm2835_audio_drain
- bcm2835_audio_close
- bcm2835_audio_write
1
2
3
4 #include <linux/slab.h>
5 #include <linux/module.h>
6 #include <linux/completion.h>
7 #include "bcm2835.h"
8 #include "vc_vchi_audioserv_defs.h"
9
10 struct bcm2835_audio_instance {
11 struct device *dev;
12 VCHI_SERVICE_HANDLE_T vchi_handle;
13 struct completion msg_avail_comp;
14 struct mutex vchi_mutex;
15 struct bcm2835_alsa_stream *alsa_stream;
16 int result;
17 unsigned int max_packet;
18 short peer_version;
19 };
20
21 static bool force_bulk;
22 module_param(force_bulk, bool, 0444);
23 MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
24
25 static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
26 {
27 mutex_lock(&instance->vchi_mutex);
28 vchi_service_use(instance->vchi_handle);
29 }
30
31 static void bcm2835_audio_unlock(struct bcm2835_audio_instance *instance)
32 {
33 vchi_service_release(instance->vchi_handle);
34 mutex_unlock(&instance->vchi_mutex);
35 }
36
37 static int bcm2835_audio_send_msg_locked(struct bcm2835_audio_instance *instance,
38 struct vc_audio_msg *m, bool wait)
39 {
40 int status;
41
42 if (wait) {
43 instance->result = -1;
44 init_completion(&instance->msg_avail_comp);
45 }
46
47 status = vchi_queue_kernel_message(instance->vchi_handle,
48 m, sizeof(*m));
49 if (status) {
50 dev_err(instance->dev,
51 "vchi message queue failed: %d, msg=%d\n",
52 status, m->type);
53 return -EIO;
54 }
55
56 if (wait) {
57 if (!wait_for_completion_timeout(&instance->msg_avail_comp,
58 msecs_to_jiffies(10 * 1000))) {
59 dev_err(instance->dev,
60 "vchi message timeout, msg=%d\n", m->type);
61 return -ETIMEDOUT;
62 } else if (instance->result) {
63 dev_err(instance->dev,
64 "vchi message response error:%d, msg=%d\n",
65 instance->result, m->type);
66 return -EIO;
67 }
68 }
69
70 return 0;
71 }
72
73 static int bcm2835_audio_send_msg(struct bcm2835_audio_instance *instance,
74 struct vc_audio_msg *m, bool wait)
75 {
76 int err;
77
78 bcm2835_audio_lock(instance);
79 err = bcm2835_audio_send_msg_locked(instance, m, wait);
80 bcm2835_audio_unlock(instance);
81 return err;
82 }
83
84 static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance,
85 int type, bool wait)
86 {
87 struct vc_audio_msg m = { .type = type };
88
89 return bcm2835_audio_send_msg(instance, &m, wait);
90 }
91
92 static void audio_vchi_callback(void *param,
93 const VCHI_CALLBACK_REASON_T reason,
94 void *msg_handle)
95 {
96 struct bcm2835_audio_instance *instance = param;
97 struct vc_audio_msg m;
98 int msg_len;
99 int status;
100
101 if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
102 return;
103
104 status = vchi_msg_dequeue(instance->vchi_handle,
105 &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
106 if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
107 instance->result = m.result.success;
108 complete(&instance->msg_avail_comp);
109 } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
110 if (m.complete.cookie1 != VC_AUDIO_WRITE_COOKIE1 ||
111 m.complete.cookie2 != VC_AUDIO_WRITE_COOKIE2)
112 dev_err(instance->dev, "invalid cookie\n");
113 else
114 bcm2835_playback_fifo(instance->alsa_stream,
115 m.complete.count);
116 } else {
117 dev_err(instance->dev, "unexpected callback type=%d\n", m.type);
118 }
119 }
120
121 static int
122 vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
123 struct bcm2835_audio_instance *instance)
124 {
125 struct service_creation params = {
126 .version = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
127 .service_id = VC_AUDIO_SERVER_NAME,
128 .callback = audio_vchi_callback,
129 .callback_param = instance,
130 };
131 int status;
132
133
134 status = vchi_service_open(vchi_instance, ¶ms,
135 &instance->vchi_handle);
136
137 if (status) {
138 dev_err(instance->dev,
139 "failed to open VCHI service connection (status=%d)\n",
140 status);
141 return -EPERM;
142 }
143
144
145 vchi_service_release(instance->vchi_handle);
146
147 return 0;
148 }
149
150 static void vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
151 {
152 int status;
153
154 mutex_lock(&instance->vchi_mutex);
155 vchi_service_use(instance->vchi_handle);
156
157
158 status = vchi_service_close(instance->vchi_handle);
159 if (status) {
160 dev_err(instance->dev,
161 "failed to close VCHI service connection (status=%d)\n",
162 status);
163 }
164
165 mutex_unlock(&instance->vchi_mutex);
166 }
167
168 int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx)
169 {
170 int ret;
171
172
173 ret = vchi_initialise(&vchi_ctx->vchi_instance);
174 if (ret) {
175 dev_err(dev, "failed to initialise VCHI instance (ret=%d)\n",
176 ret);
177 return -EIO;
178 }
179
180 ret = vchi_connect(vchi_ctx->vchi_instance);
181 if (ret) {
182 dev_dbg(dev, "failed to connect VCHI instance (ret=%d)\n",
183 ret);
184
185 kfree(vchi_ctx->vchi_instance);
186 vchi_ctx->vchi_instance = NULL;
187
188 return -EIO;
189 }
190
191 return 0;
192 }
193
194 void bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
195 {
196
197 WARN_ON(vchi_disconnect(vchi_ctx->vchi_instance));
198
199 vchi_ctx->vchi_instance = NULL;
200 }
201
202 int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
203 {
204 struct bcm2835_vchi_ctx *vchi_ctx = alsa_stream->chip->vchi_ctx;
205 struct bcm2835_audio_instance *instance;
206 int err;
207
208
209 instance = kzalloc(sizeof(*instance), GFP_KERNEL);
210 if (!instance)
211 return -ENOMEM;
212 mutex_init(&instance->vchi_mutex);
213 instance->dev = alsa_stream->chip->dev;
214 instance->alsa_stream = alsa_stream;
215 alsa_stream->instance = instance;
216
217 err = vc_vchi_audio_init(vchi_ctx->vchi_instance,
218 instance);
219 if (err < 0)
220 goto free_instance;
221
222 err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
223 false);
224 if (err < 0)
225 goto deinit;
226
227 bcm2835_audio_lock(instance);
228 vchi_get_peer_version(instance->vchi_handle, &instance->peer_version);
229 bcm2835_audio_unlock(instance);
230 if (instance->peer_version < 2 || force_bulk)
231 instance->max_packet = 0;
232 else
233 instance->max_packet = 4000;
234
235 return 0;
236
237 deinit:
238 vc_vchi_audio_deinit(instance);
239 free_instance:
240 alsa_stream->instance = NULL;
241 kfree(instance);
242 return err;
243 }
244
245 int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
246 {
247 struct bcm2835_chip *chip = alsa_stream->chip;
248 struct vc_audio_msg m = {};
249
250 m.type = VC_AUDIO_MSG_TYPE_CONTROL;
251 m.control.dest = chip->dest;
252 if (!chip->mute)
253 m.control.volume = CHIP_MIN_VOLUME;
254 else
255 m.control.volume = alsa2chip(chip->volume);
256
257 return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
258 }
259
260 int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
261 unsigned int channels, unsigned int samplerate,
262 unsigned int bps)
263 {
264 struct vc_audio_msg m = {
265 .type = VC_AUDIO_MSG_TYPE_CONFIG,
266 .config.channels = channels,
267 .config.samplerate = samplerate,
268 .config.bps = bps,
269 };
270 int err;
271
272
273 err = bcm2835_audio_set_ctls(alsa_stream);
274 if (err)
275 return err;
276
277 return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
278 }
279
280 int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
281 {
282 return bcm2835_audio_send_simple(alsa_stream->instance,
283 VC_AUDIO_MSG_TYPE_START, false);
284 }
285
286 int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
287 {
288 return bcm2835_audio_send_simple(alsa_stream->instance,
289 VC_AUDIO_MSG_TYPE_STOP, false);
290 }
291
292
293 int bcm2835_audio_drain(struct bcm2835_alsa_stream *alsa_stream)
294 {
295 struct vc_audio_msg m = {
296 .type = VC_AUDIO_MSG_TYPE_STOP,
297 .stop.draining = 1,
298 };
299
300 return bcm2835_audio_send_msg(alsa_stream->instance, &m, false);
301 }
302
303 int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
304 {
305 struct bcm2835_audio_instance *instance = alsa_stream->instance;
306 int err;
307
308 err = bcm2835_audio_send_simple(alsa_stream->instance,
309 VC_AUDIO_MSG_TYPE_CLOSE, true);
310
311
312 vc_vchi_audio_deinit(instance);
313 alsa_stream->instance = NULL;
314 kfree(instance);
315
316 return err;
317 }
318
319 int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
320 unsigned int size, void *src)
321 {
322 struct bcm2835_audio_instance *instance = alsa_stream->instance;
323 struct vc_audio_msg m = {
324 .type = VC_AUDIO_MSG_TYPE_WRITE,
325 .write.count = size,
326 .write.max_packet = instance->max_packet,
327 .write.cookie1 = VC_AUDIO_WRITE_COOKIE1,
328 .write.cookie2 = VC_AUDIO_WRITE_COOKIE2,
329 };
330 unsigned int count;
331 int err, status;
332
333 if (!size)
334 return 0;
335
336 bcm2835_audio_lock(instance);
337 err = bcm2835_audio_send_msg_locked(instance, &m, false);
338 if (err < 0)
339 goto unlock;
340
341 count = size;
342 if (!instance->max_packet) {
343
344 status = vchi_bulk_queue_transmit(instance->vchi_handle,
345 src, count,
346 VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
347 NULL);
348 } else {
349 while (count > 0) {
350 int bytes = min(instance->max_packet, count);
351
352 status = vchi_queue_kernel_message(instance->vchi_handle,
353 src, bytes);
354 src += bytes;
355 count -= bytes;
356 }
357 }
358
359 if (status) {
360 dev_err(instance->dev,
361 "failed on %d bytes transfer (status=%d)\n",
362 size, status);
363 err = -EIO;
364 }
365
366 unlock:
367 bcm2835_audio_unlock(instance);
368 return err;
369 }