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