1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2011 Broadcom Corporation. All rights reserved. */
3
4 #include <linux/device.h>
5 #include <sound/core.h>
6 #include <sound/initval.h>
7 #include <sound/pcm.h>
8 #include <linux/io.h>
9 #include <linux/interrupt.h>
10 #include <linux/fs.h>
11 #include <linux/file.h>
12 #include <linux/mm.h>
13 #include <linux/syscalls.h>
14 #include <linux/uaccess.h>
15 #include <linux/slab.h>
16 #include <linux/delay.h>
17 #include <linux/atomic.h>
18 #include <linux/module.h>
19 #include <linux/completion.h>
20
21 #include "bcm2835.h"
22
23 /* ---- Include Files -------------------------------------------------------- */
24
25 #include "vc_vchi_audioserv_defs.h"
26
27 /* ---- Private Constants and Types ------------------------------------------ */
28
29 #define BCM2835_AUDIO_STOP 0
30 #define BCM2835_AUDIO_START 1
31 #define BCM2835_AUDIO_WRITE 2
32
33 /* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
34 #ifdef AUDIO_DEBUG_ENABLE
35 #define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
36 #define LOG_WARN(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
37 #define LOG_INFO(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
38 #define LOG_DBG(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
39 #else
40 #define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
41 #define LOG_WARN(fmt, arg...) no_printk(fmt, ##arg)
42 #define LOG_INFO(fmt, arg...) no_printk(fmt, ##arg)
43 #define LOG_DBG(fmt, arg...) no_printk(fmt, ##arg)
44 #endif
45
46 struct bcm2835_audio_instance {
47 unsigned int num_connections;
48 VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
49 struct completion msg_avail_comp;
50 struct mutex vchi_mutex;
51 struct bcm2835_alsa_stream *alsa_stream;
52 int result;
53 short peer_version;
54 };
55
56 static bool force_bulk;
57
58 /* ---- Private Variables ---------------------------------------------------- */
59
60 /* ---- Private Function Prototypes ------------------------------------------ */
61
62 /* ---- Private Functions ---------------------------------------------------- */
63
64 static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream);
65 static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream);
66 static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
67 unsigned int count, void *src);
68
69 // Routine to send a message across a service
70
71 static int
bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,void * data,unsigned int size)72 bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
73 void *data,
74 unsigned int size)
75 {
76 return vchi_queue_kernel_message(handle,
77 data,
78 size);
79 }
80
81 static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 |
82 'M' << 8 | 'A');
83 static const u32 BCM2835_AUDIO_WRITE_COOKIE2 = ('D' << 24 | 'A' << 16 |
84 'T' << 8 | 'A');
85
86 struct bcm2835_audio_work {
87 struct work_struct my_work;
88 struct bcm2835_alsa_stream *alsa_stream;
89 int cmd;
90 void *src;
91 unsigned int count;
92 };
93
my_wq_function(struct work_struct * work)94 static void my_wq_function(struct work_struct *work)
95 {
96 struct bcm2835_audio_work *w =
97 container_of(work, struct bcm2835_audio_work, my_work);
98 int ret = -9;
99
100 switch (w->cmd) {
101 case BCM2835_AUDIO_START:
102 ret = bcm2835_audio_start_worker(w->alsa_stream);
103 break;
104 case BCM2835_AUDIO_STOP:
105 ret = bcm2835_audio_stop_worker(w->alsa_stream);
106 break;
107 case BCM2835_AUDIO_WRITE:
108 ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
109 w->src);
110 break;
111 default:
112 LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
113 break;
114 }
115 kfree((void *)work);
116 }
117
bcm2835_audio_start(struct bcm2835_alsa_stream * alsa_stream)118 int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
119 {
120 struct bcm2835_audio_work *work;
121
122 work = kmalloc(sizeof(*work), GFP_ATOMIC);
123 /*--- Queue some work (item 1) ---*/
124 if (!work) {
125 LOG_ERR(" .. Error: NULL work kmalloc\n");
126 return -ENOMEM;
127 }
128 INIT_WORK(&work->my_work, my_wq_function);
129 work->alsa_stream = alsa_stream;
130 work->cmd = BCM2835_AUDIO_START;
131 if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
132 kfree(work);
133 return -EBUSY;
134 }
135 return 0;
136 }
137
bcm2835_audio_stop(struct bcm2835_alsa_stream * alsa_stream)138 int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
139 {
140 struct bcm2835_audio_work *work;
141
142 work = kmalloc(sizeof(*work), GFP_ATOMIC);
143 /*--- Queue some work (item 1) ---*/
144 if (!work) {
145 LOG_ERR(" .. Error: NULL work kmalloc\n");
146 return -ENOMEM;
147 }
148 INIT_WORK(&work->my_work, my_wq_function);
149 work->alsa_stream = alsa_stream;
150 work->cmd = BCM2835_AUDIO_STOP;
151 if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
152 kfree(work);
153 return -EBUSY;
154 }
155 return 0;
156 }
157
bcm2835_audio_write(struct bcm2835_alsa_stream * alsa_stream,unsigned int count,void * src)158 int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
159 unsigned int count, void *src)
160 {
161 struct bcm2835_audio_work *work;
162
163 work = kmalloc(sizeof(*work), GFP_ATOMIC);
164 /*--- Queue some work (item 1) ---*/
165 if (!work) {
166 LOG_ERR(" .. Error: NULL work kmalloc\n");
167 return -ENOMEM;
168 }
169 INIT_WORK(&work->my_work, my_wq_function);
170 work->alsa_stream = alsa_stream;
171 work->cmd = BCM2835_AUDIO_WRITE;
172 work->src = src;
173 work->count = count;
174 if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
175 kfree(work);
176 return -EBUSY;
177 }
178 return 0;
179 }
180
my_workqueue_quit(struct bcm2835_alsa_stream * alsa_stream)181 static void my_workqueue_quit(struct bcm2835_alsa_stream *alsa_stream)
182 {
183 flush_workqueue(alsa_stream->my_wq);
184 destroy_workqueue(alsa_stream->my_wq);
185 alsa_stream->my_wq = NULL;
186 }
187
audio_vchi_callback(void * param,const VCHI_CALLBACK_REASON_T reason,void * msg_handle)188 static void audio_vchi_callback(void *param,
189 const VCHI_CALLBACK_REASON_T reason,
190 void *msg_handle)
191 {
192 struct bcm2835_audio_instance *instance = param;
193 int status;
194 int msg_len;
195 struct vc_audio_msg m;
196
197 if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
198 return;
199
200 if (!instance) {
201 LOG_ERR(" .. instance is null\n");
202 BUG();
203 return;
204 }
205 if (!instance->vchi_handle[0]) {
206 LOG_ERR(" .. instance->vchi_handle[0] is null\n");
207 BUG();
208 return;
209 }
210 status = vchi_msg_dequeue(instance->vchi_handle[0],
211 &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
212 if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
213 LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
214 instance, m.u.result.success);
215 instance->result = m.u.result.success;
216 complete(&instance->msg_avail_comp);
217 } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
218 struct bcm2835_alsa_stream *alsa_stream = instance->alsa_stream;
219
220 LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
221 instance, m.u.complete.count);
222 if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
223 m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
224 LOG_ERR(" .. response is corrupt\n");
225 else if (alsa_stream) {
226 atomic_add(m.u.complete.count,
227 &alsa_stream->retrieved);
228 bcm2835_playback_fifo(alsa_stream);
229 } else {
230 LOG_ERR(" .. unexpected alsa_stream=%p\n",
231 alsa_stream);
232 }
233 } else {
234 LOG_ERR(" .. unexpected m.type=%d\n", m.type);
235 }
236 }
237
238 static struct bcm2835_audio_instance *
vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,VCHI_CONNECTION_T ** vchi_connections,unsigned int num_connections)239 vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
240 VCHI_CONNECTION_T **vchi_connections,
241 unsigned int num_connections)
242 {
243 unsigned int i;
244 struct bcm2835_audio_instance *instance;
245 int status;
246 int ret;
247
248 LOG_DBG("%s: start", __func__);
249
250 if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
251 LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
252 __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
253
254 return ERR_PTR(-EINVAL);
255 }
256 /* Allocate memory for this instance */
257 instance = kzalloc(sizeof(*instance), GFP_KERNEL);
258 if (!instance)
259 return ERR_PTR(-ENOMEM);
260
261 instance->num_connections = num_connections;
262
263 /* Create a lock for exclusive, serialized VCHI connection access */
264 mutex_init(&instance->vchi_mutex);
265 /* Open the VCHI service connections */
266 for (i = 0; i < num_connections; i++) {
267 SERVICE_CREATION_T params = {
268 .version = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
269 .service_id = VC_AUDIO_SERVER_NAME,
270 .connection = vchi_connections[i],
271 .rx_fifo_size = 0,
272 .tx_fifo_size = 0,
273 .callback = audio_vchi_callback,
274 .callback_param = instance,
275 .want_unaligned_bulk_rx = 1, //TODO: remove VCOS_FALSE
276 .want_unaligned_bulk_tx = 1, //TODO: remove VCOS_FALSE
277 .want_crc = 0
278 };
279
280 LOG_DBG("%s: about to open %i\n", __func__, i);
281 status = vchi_service_open(vchi_instance, ¶ms,
282 &instance->vchi_handle[i]);
283
284 LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
285 if (status) {
286 LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
287 __func__, status);
288 ret = -EPERM;
289 goto err_close_services;
290 }
291 /* Finished with the service for now */
292 vchi_service_release(instance->vchi_handle[i]);
293 }
294
295 LOG_DBG("%s: okay\n", __func__);
296 return instance;
297
298 err_close_services:
299 for (i = 0; i < instance->num_connections; i++) {
300 LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
301 if (instance->vchi_handle[i])
302 vchi_service_close(instance->vchi_handle[i]);
303 }
304
305 kfree(instance);
306 LOG_ERR("%s: error\n", __func__);
307
308 return ERR_PTR(ret);
309 }
310
vc_vchi_audio_deinit(struct bcm2835_audio_instance * instance)311 static int vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
312 {
313 unsigned int i;
314
315 if (!instance) {
316 LOG_ERR("%s: invalid handle %p\n", __func__, instance);
317
318 return -1;
319 }
320
321 LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
322 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
323 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
324 instance->num_connections);
325 return -EINTR;
326 }
327
328 /* Close all VCHI service connections */
329 for (i = 0; i < instance->num_connections; i++) {
330 int status;
331
332 LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
333 vchi_service_use(instance->vchi_handle[i]);
334
335 status = vchi_service_close(instance->vchi_handle[i]);
336 if (status) {
337 LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
338 __func__, status);
339 }
340 }
341
342 mutex_unlock(&instance->vchi_mutex);
343
344 kfree(instance);
345
346 return 0;
347 }
348
bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx * vchi_ctx)349 int bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
350 {
351 int ret;
352
353 /* Initialize and create a VCHI connection */
354 ret = vchi_initialise(&vchi_ctx->vchi_instance);
355 if (ret) {
356 LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
357 __func__, ret);
358
359 return -EIO;
360 }
361
362 ret = vchi_connect(NULL, 0, vchi_ctx->vchi_instance);
363 if (ret) {
364 LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
365 __func__, ret);
366
367 kfree(vchi_ctx->vchi_instance);
368 vchi_ctx->vchi_instance = NULL;
369
370 return -EIO;
371 }
372
373 return 0;
374 }
375
bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx * vchi_ctx)376 void bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
377 {
378 /* Close the VCHI connection - it will also free vchi_instance */
379 WARN_ON(vchi_disconnect(vchi_ctx->vchi_instance));
380
381 vchi_ctx->vchi_instance = NULL;
382 }
383
bcm2835_audio_open_connection(struct bcm2835_alsa_stream * alsa_stream)384 static int bcm2835_audio_open_connection(struct bcm2835_alsa_stream *alsa_stream)
385 {
386 struct bcm2835_audio_instance *instance =
387 (struct bcm2835_audio_instance *)alsa_stream->instance;
388 struct bcm2835_vchi_ctx *vhci_ctx = alsa_stream->chip->vchi_ctx;
389
390 LOG_INFO("%s: start\n", __func__);
391 BUG_ON(instance);
392 if (instance) {
393 LOG_ERR("%s: VCHI instance already open (%p)\n",
394 __func__, instance);
395 instance->alsa_stream = alsa_stream;
396 alsa_stream->instance = instance;
397 return 0;
398 }
399
400 /* Initialize an instance of the audio service */
401 instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
402 &vhci_ctx->vchi_connection, 1);
403
404 if (IS_ERR(instance)) {
405 LOG_ERR("%s: failed to initialize audio service\n", __func__);
406
407 /* vchi_instance is retained for use the next time. */
408 return PTR_ERR(instance);
409 }
410
411 instance->alsa_stream = alsa_stream;
412 alsa_stream->instance = instance;
413
414 LOG_DBG(" success !\n");
415
416 return 0;
417 }
418
bcm2835_audio_open(struct bcm2835_alsa_stream * alsa_stream)419 int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
420 {
421 struct bcm2835_audio_instance *instance;
422 struct vc_audio_msg m;
423 int status;
424 int ret;
425
426 alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
427 if (!alsa_stream->my_wq)
428 return -ENOMEM;
429
430 ret = bcm2835_audio_open_connection(alsa_stream);
431 if (ret)
432 goto free_wq;
433
434 instance = alsa_stream->instance;
435 LOG_DBG(" instance (%p)\n", instance);
436
437 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
438 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
439 ret = -EINTR;
440 goto free_wq;
441 }
442 vchi_service_use(instance->vchi_handle[0]);
443
444 m.type = VC_AUDIO_MSG_TYPE_OPEN;
445
446 /* Send the message to the videocore */
447 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
448 &m, sizeof(m));
449
450 if (status) {
451 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
452 __func__, status);
453
454 ret = -1;
455 goto unlock;
456 }
457
458 ret = 0;
459
460 unlock:
461 vchi_service_release(instance->vchi_handle[0]);
462 mutex_unlock(&instance->vchi_mutex);
463
464 free_wq:
465 if (ret)
466 destroy_workqueue(alsa_stream->my_wq);
467
468 return ret;
469 }
470
bcm2835_audio_set_ctls_chan(struct bcm2835_alsa_stream * alsa_stream,struct bcm2835_chip * chip)471 static int bcm2835_audio_set_ctls_chan(struct bcm2835_alsa_stream *alsa_stream,
472 struct bcm2835_chip *chip)
473 {
474 struct vc_audio_msg m;
475 struct bcm2835_audio_instance *instance = alsa_stream->instance;
476 int status;
477 int ret;
478
479 LOG_INFO(" Setting ALSA dest(%d), volume(%d)\n",
480 chip->dest, chip->volume);
481
482 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
483 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
484 instance->num_connections);
485 return -EINTR;
486 }
487 vchi_service_use(instance->vchi_handle[0]);
488
489 instance->result = -1;
490
491 m.type = VC_AUDIO_MSG_TYPE_CONTROL;
492 m.u.control.dest = chip->dest;
493 m.u.control.volume = chip->volume;
494
495 /* Create the message available completion */
496 init_completion(&instance->msg_avail_comp);
497
498 /* Send the message to the videocore */
499 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
500 &m, sizeof(m));
501
502 if (status) {
503 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
504 __func__, status);
505
506 ret = -1;
507 goto unlock;
508 }
509
510 /* We are expecting a reply from the videocore */
511 wait_for_completion(&instance->msg_avail_comp);
512
513 if (instance->result) {
514 LOG_ERR("%s: result=%d\n", __func__, instance->result);
515
516 ret = -1;
517 goto unlock;
518 }
519
520 ret = 0;
521
522 unlock:
523 vchi_service_release(instance->vchi_handle[0]);
524 mutex_unlock(&instance->vchi_mutex);
525
526 return ret;
527 }
528
bcm2835_audio_set_ctls(struct bcm2835_chip * chip)529 int bcm2835_audio_set_ctls(struct bcm2835_chip *chip)
530 {
531 int i;
532 int ret = 0;
533
534 LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
535
536 /* change ctls for all substreams */
537 for (i = 0; i < MAX_SUBSTREAMS; i++) {
538 if (chip->avail_substreams & (1 << i)) {
539 if (!chip->alsa_stream[i]) {
540 LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
541 ret = 0;
542 } else if (bcm2835_audio_set_ctls_chan(chip->alsa_stream[i], chip) != 0) {
543 LOG_ERR("Couldn't set the controls for stream %d\n", i);
544 ret = -1;
545 } else {
546 LOG_DBG(" Controls set for stream %d\n", i);
547 }
548 }
549 }
550 return ret;
551 }
552
bcm2835_audio_set_params(struct bcm2835_alsa_stream * alsa_stream,unsigned int channels,unsigned int samplerate,unsigned int bps)553 int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
554 unsigned int channels, unsigned int samplerate,
555 unsigned int bps)
556 {
557 struct vc_audio_msg m;
558 struct bcm2835_audio_instance *instance = alsa_stream->instance;
559 int status;
560 int ret;
561
562 LOG_INFO(" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
563 channels, samplerate, bps);
564
565 /* resend ctls - alsa_stream may not have been open when first send */
566 ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
567 if (ret) {
568 LOG_ERR(" Alsa controls not supported\n");
569 return -EINVAL;
570 }
571
572 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
573 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
574 return -EINTR;
575 }
576 vchi_service_use(instance->vchi_handle[0]);
577
578 instance->result = -1;
579
580 m.type = VC_AUDIO_MSG_TYPE_CONFIG;
581 m.u.config.channels = channels;
582 m.u.config.samplerate = samplerate;
583 m.u.config.bps = bps;
584
585 /* Create the message available completion */
586 init_completion(&instance->msg_avail_comp);
587
588 /* Send the message to the videocore */
589 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
590 &m, sizeof(m));
591
592 if (status) {
593 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
594 __func__, status);
595
596 ret = -1;
597 goto unlock;
598 }
599
600 /* We are expecting a reply from the videocore */
601 wait_for_completion(&instance->msg_avail_comp);
602
603 if (instance->result) {
604 LOG_ERR("%s: result=%d", __func__, instance->result);
605
606 ret = -1;
607 goto unlock;
608 }
609
610 ret = 0;
611
612 unlock:
613 vchi_service_release(instance->vchi_handle[0]);
614 mutex_unlock(&instance->vchi_mutex);
615
616 return ret;
617 }
618
bcm2835_audio_setup(struct bcm2835_alsa_stream * alsa_stream)619 int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream)
620 {
621
622 return 0;
623 }
624
bcm2835_audio_start_worker(struct bcm2835_alsa_stream * alsa_stream)625 static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
626 {
627 struct vc_audio_msg m;
628 struct bcm2835_audio_instance *instance = alsa_stream->instance;
629 int status;
630 int ret;
631
632 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
633 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
634 instance->num_connections);
635 return -EINTR;
636 }
637 vchi_service_use(instance->vchi_handle[0]);
638
639 m.type = VC_AUDIO_MSG_TYPE_START;
640
641 /* Send the message to the videocore */
642 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
643 &m, sizeof(m));
644
645 if (status) {
646 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
647 __func__, status);
648
649 ret = -1;
650 goto unlock;
651 }
652
653 ret = 0;
654
655 unlock:
656 vchi_service_release(instance->vchi_handle[0]);
657 mutex_unlock(&instance->vchi_mutex);
658 return ret;
659 }
660
bcm2835_audio_stop_worker(struct bcm2835_alsa_stream * alsa_stream)661 static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
662 {
663 struct vc_audio_msg m;
664 struct bcm2835_audio_instance *instance = alsa_stream->instance;
665 int status;
666 int ret;
667
668 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
669 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
670 instance->num_connections);
671 return -EINTR;
672 }
673 vchi_service_use(instance->vchi_handle[0]);
674
675 m.type = VC_AUDIO_MSG_TYPE_STOP;
676 m.u.stop.draining = alsa_stream->draining;
677
678 /* Send the message to the videocore */
679 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
680 &m, sizeof(m));
681
682 if (status) {
683 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
684 __func__, status);
685
686 ret = -1;
687 goto unlock;
688 }
689
690 ret = 0;
691
692 unlock:
693 vchi_service_release(instance->vchi_handle[0]);
694 mutex_unlock(&instance->vchi_mutex);
695 return ret;
696 }
697
bcm2835_audio_close(struct bcm2835_alsa_stream * alsa_stream)698 int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
699 {
700 struct vc_audio_msg m;
701 struct bcm2835_audio_instance *instance = alsa_stream->instance;
702 int status;
703 int ret;
704
705 my_workqueue_quit(alsa_stream);
706
707 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
708 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
709 instance->num_connections);
710 return -EINTR;
711 }
712 vchi_service_use(instance->vchi_handle[0]);
713
714 m.type = VC_AUDIO_MSG_TYPE_CLOSE;
715
716 /* Create the message available completion */
717 init_completion(&instance->msg_avail_comp);
718
719 /* Send the message to the videocore */
720 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
721 &m, sizeof(m));
722
723 if (status) {
724 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
725 __func__, status);
726 ret = -1;
727 goto unlock;
728 }
729
730 /* We are expecting a reply from the videocore */
731 wait_for_completion(&instance->msg_avail_comp);
732
733 if (instance->result) {
734 LOG_ERR("%s: failed result (result=%d)\n",
735 __func__, instance->result);
736
737 ret = -1;
738 goto unlock;
739 }
740
741 ret = 0;
742
743 unlock:
744 vchi_service_release(instance->vchi_handle[0]);
745 mutex_unlock(&instance->vchi_mutex);
746
747 /* Stop the audio service */
748 vc_vchi_audio_deinit(instance);
749 alsa_stream->instance = NULL;
750
751 return ret;
752 }
753
bcm2835_audio_write_worker(struct bcm2835_alsa_stream * alsa_stream,unsigned int count,void * src)754 static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
755 unsigned int count, void *src)
756 {
757 struct vc_audio_msg m;
758 struct bcm2835_audio_instance *instance = alsa_stream->instance;
759 int status;
760 int ret;
761
762 LOG_INFO(" Writing %d bytes from %p\n", count, src);
763
764 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
765 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
766 instance->num_connections);
767 return -EINTR;
768 }
769 vchi_service_use(instance->vchi_handle[0]);
770
771 if (instance->peer_version == 0 &&
772 vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0)
773 LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
774
775 m.type = VC_AUDIO_MSG_TYPE_WRITE;
776 m.u.write.count = count;
777 // old version uses bulk, new version uses control
778 m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0 : 4000;
779 m.u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1;
780 m.u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2;
781 m.u.write.silence = src == NULL;
782
783 /* Send the message to the videocore */
784 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
785 &m, sizeof(m));
786
787 if (status) {
788 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
789 __func__, status);
790
791 ret = -1;
792 goto unlock;
793 }
794 if (!m.u.write.silence) {
795 if (!m.u.write.max_packet) {
796 /* Send the message to the videocore */
797 status = vchi_bulk_queue_transmit(instance->vchi_handle[0],
798 src, count,
799 0 * VCHI_FLAGS_BLOCK_UNTIL_QUEUED
800 +
801 1 * VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
802 NULL);
803 } else {
804 while (count > 0) {
805 int bytes = min_t(int, m.u.write.max_packet, count);
806
807 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
808 src, bytes);
809 src = (char *)src + bytes;
810 count -= bytes;
811 }
812 }
813 if (status) {
814 LOG_ERR("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
815 __func__, status);
816
817 ret = -1;
818 goto unlock;
819 }
820 }
821 ret = 0;
822
823 unlock:
824 vchi_service_release(instance->vchi_handle[0]);
825 mutex_unlock(&instance->vchi_mutex);
826 return ret;
827 }
828
829 /**
830 * Returns all buffers from arm->vc
831 */
bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream * alsa_stream)832 void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream)
833 {
834 }
835
836 /**
837 * Forces VC to flush(drop) its filled playback buffers and
838 * return them the us. (VC->ARM)
839 */
bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream * alsa_stream)840 void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream)
841 {
842 }
843
bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream * alsa_stream)844 unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
845 {
846 unsigned int count = atomic_read(&alsa_stream->retrieved);
847
848 atomic_sub(count, &alsa_stream->retrieved);
849 return count;
850 }
851
852 module_param(force_bulk, bool, 0444);
853 MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
854