]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/staging/bcm2835-audio/bcm2835-vchiq.c
Merge tag 'rtc-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
[mirror_ubuntu-artful-kernel.git] / drivers / staging / 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 LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
113 switch (w->cmd) {
114 case BCM2835_AUDIO_START:
115 ret = bcm2835_audio_start_worker(w->alsa_stream);
116 break;
117 case BCM2835_AUDIO_STOP:
118 ret = bcm2835_audio_stop_worker(w->alsa_stream);
119 break;
120 case BCM2835_AUDIO_WRITE:
121 ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
122 w->src);
123 break;
124 default:
125 LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
126 break;
127 }
128 kfree((void *) work);
129 LOG_DBG(" .. OUT %d\n", ret);
130 }
131
132 int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
133 {
134 int ret = -1;
135
136 LOG_DBG(" .. IN\n");
137 if (alsa_stream->my_wq) {
138 struct bcm2835_audio_work *work;
139
140 work = kmalloc(sizeof(*work), GFP_ATOMIC);
141 /*--- Queue some work (item 1) ---*/
142 if (work) {
143 INIT_WORK(&work->my_work, my_wq_function);
144 work->alsa_stream = alsa_stream;
145 work->cmd = BCM2835_AUDIO_START;
146 if (queue_work(alsa_stream->my_wq, &work->my_work))
147 ret = 0;
148 } else
149 LOG_ERR(" .. Error: NULL work kmalloc\n");
150 }
151 LOG_DBG(" .. OUT %d\n", ret);
152 return ret;
153 }
154
155 int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
156 {
157 int ret = -1;
158
159 LOG_DBG(" .. IN\n");
160 if (alsa_stream->my_wq) {
161 struct bcm2835_audio_work *work;
162
163 work = kmalloc(sizeof(*work), GFP_ATOMIC);
164 /*--- Queue some work (item 1) ---*/
165 if (work) {
166 INIT_WORK(&work->my_work, my_wq_function);
167 work->alsa_stream = alsa_stream;
168 work->cmd = BCM2835_AUDIO_STOP;
169 if (queue_work(alsa_stream->my_wq, &work->my_work))
170 ret = 0;
171 } else
172 LOG_ERR(" .. Error: NULL work kmalloc\n");
173 }
174 LOG_DBG(" .. OUT %d\n", ret);
175 return ret;
176 }
177
178 int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
179 unsigned int count, void *src)
180 {
181 int ret = -1;
182
183 LOG_DBG(" .. IN\n");
184 if (alsa_stream->my_wq) {
185 struct bcm2835_audio_work *work;
186
187 work = kmalloc(sizeof(*work), GFP_ATOMIC);
188 /*--- Queue some work (item 1) ---*/
189 if (work) {
190 INIT_WORK(&work->my_work, my_wq_function);
191 work->alsa_stream = alsa_stream;
192 work->cmd = BCM2835_AUDIO_WRITE;
193 work->src = src;
194 work->count = count;
195 if (queue_work(alsa_stream->my_wq, &work->my_work))
196 ret = 0;
197 } else
198 LOG_ERR(" .. Error: NULL work kmalloc\n");
199 }
200 LOG_DBG(" .. OUT %d\n", ret);
201 return ret;
202 }
203
204 static void my_workqueue_init(struct bcm2835_alsa_stream *alsa_stream)
205 {
206 alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
207 return;
208 }
209
210 static void my_workqueue_quit(struct bcm2835_alsa_stream *alsa_stream)
211 {
212 if (alsa_stream->my_wq) {
213 flush_workqueue(alsa_stream->my_wq);
214 destroy_workqueue(alsa_stream->my_wq);
215 alsa_stream->my_wq = NULL;
216 }
217 return;
218 }
219
220 static void audio_vchi_callback(void *param,
221 const VCHI_CALLBACK_REASON_T reason,
222 void *msg_handle)
223 {
224 struct bcm2835_audio_instance *instance = param;
225 int status;
226 int msg_len;
227 struct vc_audio_msg m;
228
229 LOG_DBG(" .. IN instance=%p, handle=%p, alsa=%p, reason=%d, handle=%p\n",
230 instance, instance ? instance->vchi_handle[0] : NULL, instance ? instance->alsa_stream : NULL, reason, msg_handle);
231
232 if (reason != VCHI_CALLBACK_MSG_AVAILABLE) {
233 return;
234 }
235 if (!instance) {
236 LOG_ERR(" .. instance is null\n");
237 BUG();
238 return;
239 }
240 if (!instance->vchi_handle[0]) {
241 LOG_ERR(" .. instance->vchi_handle[0] is null\n");
242 BUG();
243 return;
244 }
245 status = vchi_msg_dequeue(instance->vchi_handle[0],
246 &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
247 if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
248 LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
249 instance, m.u.result.success);
250 instance->result = m.u.result.success;
251 complete(&instance->msg_avail_comp);
252 } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
253 struct bcm2835_alsa_stream *alsa_stream = instance->alsa_stream;
254
255 LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
256 instance, m.u.complete.count);
257 if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
258 m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
259 LOG_ERR(" .. response is corrupt\n");
260 else if (alsa_stream) {
261 atomic_add(m.u.complete.count,
262 &alsa_stream->retrieved);
263 bcm2835_playback_fifo(alsa_stream);
264 } else {
265 LOG_ERR(" .. unexpected alsa_stream=%p\n",
266 alsa_stream);
267 }
268 } else {
269 LOG_ERR(" .. unexpected m.type=%d\n", m.type);
270 }
271 LOG_DBG(" .. OUT\n");
272 }
273
274 static struct bcm2835_audio_instance *
275 vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
276 VCHI_CONNECTION_T **vchi_connections,
277 unsigned int num_connections)
278 {
279 unsigned int i;
280 struct bcm2835_audio_instance *instance;
281 int status;
282
283 LOG_DBG("%s: start", __func__);
284
285 if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
286 LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
287 __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
288
289 return NULL;
290 }
291 /* Allocate memory for this instance */
292 instance = kmalloc(sizeof(*instance), GFP_KERNEL);
293 if (!instance)
294 return NULL;
295
296 memset(instance, 0, sizeof(*instance));
297 instance->num_connections = num_connections;
298
299 /* Create a lock for exclusive, serialized VCHI connection access */
300 mutex_init(&instance->vchi_mutex);
301 /* Open the VCHI service connections */
302 for (i = 0; i < num_connections; i++) {
303 SERVICE_CREATION_T params = {
304 VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
305 VC_AUDIO_SERVER_NAME, // 4cc service code
306 vchi_connections[i], // passed in fn pointers
307 0, // rx fifo size (unused)
308 0, // tx fifo size (unused)
309 audio_vchi_callback, // service callback
310 instance, // service callback parameter
311 1, //TODO: remove VCOS_FALSE, // unaligned bulk recieves
312 1, //TODO: remove VCOS_FALSE, // unaligned bulk transmits
313 0 // want crc check on bulk transfers
314 };
315
316 LOG_DBG("%s: about to open %i\n", __func__, i);
317 status = vchi_service_open(vchi_instance, &params,
318 &instance->vchi_handle[i]);
319 LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
320 if (status) {
321 LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
322 __func__, status);
323
324 goto err_close_services;
325 }
326 /* Finished with the service for now */
327 vchi_service_release(instance->vchi_handle[i]);
328 }
329
330 LOG_DBG("%s: okay\n", __func__);
331 return instance;
332
333 err_close_services:
334 for (i = 0; i < instance->num_connections; i++) {
335 LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
336 if (instance->vchi_handle[i])
337 vchi_service_close(instance->vchi_handle[i]);
338 }
339
340 kfree(instance);
341 LOG_ERR("%s: error\n", __func__);
342
343 return NULL;
344 }
345
346 static int vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
347 {
348 unsigned int i;
349
350 LOG_DBG(" .. IN\n");
351
352 if (!instance) {
353 LOG_ERR("%s: invalid handle %p\n", __func__, instance);
354
355 return -1;
356 }
357
358 LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
359 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
360 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
361 instance->num_connections);
362 return -EINTR;
363 }
364
365 /* Close all VCHI service connections */
366 for (i = 0; i < instance->num_connections; i++) {
367 int status;
368
369 LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
370 vchi_service_use(instance->vchi_handle[i]);
371
372 status = vchi_service_close(instance->vchi_handle[i]);
373 if (status) {
374 LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
375 __func__, status);
376 }
377 }
378
379 mutex_unlock(&instance->vchi_mutex);
380
381 kfree(instance);
382
383 LOG_DBG(" .. OUT\n");
384
385 return 0;
386 }
387
388 static int bcm2835_audio_open_connection(struct bcm2835_alsa_stream *alsa_stream)
389 {
390 static VCHI_INSTANCE_T vchi_instance;
391 static VCHI_CONNECTION_T *vchi_connection;
392 static int initted;
393 struct bcm2835_audio_instance *instance =
394 (struct bcm2835_audio_instance *)alsa_stream->instance;
395 int ret;
396
397 LOG_DBG(" .. IN\n");
398
399 LOG_INFO("%s: start\n", __func__);
400 BUG_ON(instance);
401 if (instance) {
402 LOG_ERR("%s: VCHI instance already open (%p)\n",
403 __func__, instance);
404 instance->alsa_stream = alsa_stream;
405 alsa_stream->instance = instance;
406 ret = 0; // xxx todo -1;
407 goto err_free_mem;
408 }
409
410 /* Initialize and create a VCHI connection */
411 if (!initted) {
412 ret = vchi_initialise(&vchi_instance);
413 if (ret) {
414 LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
415 __func__, ret);
416
417 ret = -EIO;
418 goto err_free_mem;
419 }
420 ret = vchi_connect(NULL, 0, vchi_instance);
421 if (ret) {
422 LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
423 __func__, ret);
424
425 ret = -EIO;
426 goto err_free_mem;
427 }
428 initted = 1;
429 }
430
431 /* Initialize an instance of the audio service */
432 instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
433
434 if (!instance) {
435 LOG_ERR("%s: failed to initialize audio service\n", __func__);
436
437 ret = -EPERM;
438 goto err_free_mem;
439 }
440
441 instance->alsa_stream = alsa_stream;
442 alsa_stream->instance = instance;
443
444 LOG_DBG(" success !\n");
445 ret = 0;
446 err_free_mem:
447 LOG_DBG(" .. OUT\n");
448
449 return ret;
450 }
451
452 int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
453 {
454 struct bcm2835_audio_instance *instance;
455 struct vc_audio_msg m;
456 int status;
457 int ret;
458
459 LOG_DBG(" .. IN\n");
460
461 my_workqueue_init(alsa_stream);
462
463 ret = bcm2835_audio_open_connection(alsa_stream);
464 if (ret) {
465 ret = -1;
466 goto exit;
467 }
468 instance = alsa_stream->instance;
469 LOG_DBG(" instance (%p)\n", instance);
470
471 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
472 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
473 return -EINTR;
474 }
475 vchi_service_use(instance->vchi_handle[0]);
476
477 m.type = VC_AUDIO_MSG_TYPE_OPEN;
478
479 /* Send the message to the videocore */
480 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
481 &m, sizeof(m));
482
483 if (status) {
484 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
485 __func__, status);
486
487 ret = -1;
488 goto unlock;
489 }
490
491 ret = 0;
492
493 unlock:
494 vchi_service_release(instance->vchi_handle[0]);
495 mutex_unlock(&instance->vchi_mutex);
496 exit:
497 LOG_DBG(" .. OUT\n");
498 return ret;
499 }
500
501 static int bcm2835_audio_set_ctls_chan(struct bcm2835_alsa_stream *alsa_stream,
502 struct bcm2835_chip *chip)
503 {
504 struct vc_audio_msg m;
505 struct bcm2835_audio_instance *instance = alsa_stream->instance;
506 int status;
507 int ret;
508
509 LOG_DBG(" .. IN\n");
510
511 LOG_INFO(" Setting ALSA dest(%d), volume(%d)\n",
512 chip->dest, chip->volume);
513
514 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
515 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
516 instance->num_connections);
517 return -EINTR;
518 }
519 vchi_service_use(instance->vchi_handle[0]);
520
521 instance->result = -1;
522
523 m.type = VC_AUDIO_MSG_TYPE_CONTROL;
524 m.u.control.dest = chip->dest;
525 m.u.control.volume = chip->volume;
526
527 /* Create the message available completion */
528 init_completion(&instance->msg_avail_comp);
529
530 /* Send the message to the videocore */
531 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
532 &m, sizeof(m));
533
534 if (status) {
535 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
536 __func__, status);
537
538 ret = -1;
539 goto unlock;
540 }
541
542 /* We are expecting a reply from the videocore */
543 wait_for_completion(&instance->msg_avail_comp);
544
545 if (instance->result) {
546 LOG_ERR("%s: result=%d\n", __func__, instance->result);
547
548 ret = -1;
549 goto unlock;
550 }
551
552 ret = 0;
553
554 unlock:
555 vchi_service_release(instance->vchi_handle[0]);
556 mutex_unlock(&instance->vchi_mutex);
557
558 LOG_DBG(" .. OUT\n");
559 return ret;
560 }
561
562 int bcm2835_audio_set_ctls(struct bcm2835_chip *chip)
563 {
564 int i;
565 int ret = 0;
566
567 LOG_DBG(" .. IN\n");
568 LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
569
570 /* change ctls for all substreams */
571 for (i = 0; i < MAX_SUBSTREAMS; i++) {
572 if (chip->avail_substreams & (1 << i)) {
573 if (!chip->alsa_stream[i]) {
574 LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
575 ret = 0;
576 } else if (bcm2835_audio_set_ctls_chan(chip->alsa_stream[i], chip) != 0) {
577 LOG_ERR("Couldn't set the controls for stream %d\n", i);
578 ret = -1;
579 } else {
580 LOG_DBG(" Controls set for stream %d\n", i);
581 }
582 }
583 }
584 LOG_DBG(" .. OUT ret=%d\n", ret);
585 return ret;
586 }
587
588 int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
589 unsigned int channels, unsigned int samplerate,
590 unsigned int bps)
591 {
592 struct vc_audio_msg m;
593 struct bcm2835_audio_instance *instance = alsa_stream->instance;
594 int status;
595 int ret;
596
597 LOG_DBG(" .. IN\n");
598
599 LOG_INFO(" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
600 channels, samplerate, bps);
601
602 /* resend ctls - alsa_stream may not have been open when first send */
603 ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
604 if (ret) {
605 LOG_ERR(" Alsa controls not supported\n");
606 return -EINVAL;
607 }
608
609 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
610 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
611 return -EINTR;
612 }
613 vchi_service_use(instance->vchi_handle[0]);
614
615 instance->result = -1;
616
617 m.type = VC_AUDIO_MSG_TYPE_CONFIG;
618 m.u.config.channels = channels;
619 m.u.config.samplerate = samplerate;
620 m.u.config.bps = bps;
621
622 /* Create the message available completion */
623 init_completion(&instance->msg_avail_comp);
624
625 /* Send the message to the videocore */
626 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
627 &m, sizeof(m));
628
629 if (status) {
630 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
631 __func__, status);
632
633 ret = -1;
634 goto unlock;
635 }
636
637 /* We are expecting a reply from the videocore */
638 wait_for_completion(&instance->msg_avail_comp);
639
640 if (instance->result) {
641 LOG_ERR("%s: result=%d", __func__, instance->result);
642
643 ret = -1;
644 goto unlock;
645 }
646
647 ret = 0;
648
649 unlock:
650 vchi_service_release(instance->vchi_handle[0]);
651 mutex_unlock(&instance->vchi_mutex);
652
653 LOG_DBG(" .. OUT\n");
654 return ret;
655 }
656
657 int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream)
658 {
659 LOG_DBG(" .. IN\n");
660
661 LOG_DBG(" .. OUT\n");
662
663 return 0;
664 }
665
666 static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
667 {
668 struct vc_audio_msg m;
669 struct bcm2835_audio_instance *instance = alsa_stream->instance;
670 int status;
671 int ret;
672
673 LOG_DBG(" .. IN\n");
674
675 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
676 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
677 instance->num_connections);
678 return -EINTR;
679 }
680 vchi_service_use(instance->vchi_handle[0]);
681
682 m.type = VC_AUDIO_MSG_TYPE_START;
683
684 /* Send the message to the videocore */
685 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
686 &m, sizeof(m));
687
688 if (status) {
689 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
690 __func__, status);
691
692 ret = -1;
693 goto unlock;
694 }
695
696 ret = 0;
697
698 unlock:
699 vchi_service_release(instance->vchi_handle[0]);
700 mutex_unlock(&instance->vchi_mutex);
701 LOG_DBG(" .. OUT\n");
702 return ret;
703 }
704
705 static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
706 {
707 struct vc_audio_msg m;
708 struct bcm2835_audio_instance *instance = alsa_stream->instance;
709 int status;
710 int ret;
711
712 LOG_DBG(" .. IN\n");
713
714 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
715 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
716 instance->num_connections);
717 return -EINTR;
718 }
719 vchi_service_use(instance->vchi_handle[0]);
720
721 m.type = VC_AUDIO_MSG_TYPE_STOP;
722 m.u.stop.draining = alsa_stream->draining;
723
724 /* Send the message to the videocore */
725 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
726 &m, sizeof(m));
727
728 if (status) {
729 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
730 __func__, status);
731
732 ret = -1;
733 goto unlock;
734 }
735
736 ret = 0;
737
738 unlock:
739 vchi_service_release(instance->vchi_handle[0]);
740 mutex_unlock(&instance->vchi_mutex);
741 LOG_DBG(" .. OUT\n");
742 return ret;
743 }
744
745 int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
746 {
747 struct vc_audio_msg m;
748 struct bcm2835_audio_instance *instance = alsa_stream->instance;
749 int status;
750 int ret;
751
752 LOG_DBG(" .. IN\n");
753
754 my_workqueue_quit(alsa_stream);
755
756 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
757 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
758 instance->num_connections);
759 return -EINTR;
760 }
761 vchi_service_use(instance->vchi_handle[0]);
762
763 m.type = VC_AUDIO_MSG_TYPE_CLOSE;
764
765 /* Create the message available completion */
766 init_completion(&instance->msg_avail_comp);
767
768 /* Send the message to the videocore */
769 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
770 &m, sizeof(m));
771
772 if (status) {
773 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
774 __func__, status);
775 ret = -1;
776 goto unlock;
777 }
778
779 /* We are expecting a reply from the videocore */
780 wait_for_completion(&instance->msg_avail_comp);
781
782 if (instance->result) {
783 LOG_ERR("%s: failed result (result=%d)\n",
784 __func__, instance->result);
785
786 ret = -1;
787 goto unlock;
788 }
789
790 ret = 0;
791
792 unlock:
793 vchi_service_release(instance->vchi_handle[0]);
794 mutex_unlock(&instance->vchi_mutex);
795
796 /* Stop the audio service */
797 vc_vchi_audio_deinit(instance);
798 alsa_stream->instance = NULL;
799
800 LOG_DBG(" .. OUT\n");
801 return ret;
802 }
803
804 static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
805 unsigned int count, void *src)
806 {
807 struct vc_audio_msg m;
808 struct bcm2835_audio_instance *instance = alsa_stream->instance;
809 int status;
810 int ret;
811
812 LOG_DBG(" .. IN\n");
813
814 LOG_INFO(" Writing %d bytes from %p\n", count, src);
815
816 if (mutex_lock_interruptible(&instance->vchi_mutex)) {
817 LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
818 instance->num_connections);
819 return -EINTR;
820 }
821 vchi_service_use(instance->vchi_handle[0]);
822
823 if (instance->peer_version == 0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0) {
824 LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
825 }
826 m.type = VC_AUDIO_MSG_TYPE_WRITE;
827 m.u.write.count = count;
828 // old version uses bulk, new version uses control
829 m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0 : 4000;
830 m.u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1;
831 m.u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2;
832 m.u.write.silence = src == NULL;
833
834 /* Send the message to the videocore */
835 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
836 &m, sizeof(m));
837
838 if (status) {
839 LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
840 __func__, status);
841
842 ret = -1;
843 goto unlock;
844 }
845 if (!m.u.write.silence) {
846 if (!m.u.write.max_packet) {
847 /* Send the message to the videocore */
848 status = vchi_bulk_queue_transmit(instance->vchi_handle[0],
849 src, count,
850 0 *
851 VCHI_FLAGS_BLOCK_UNTIL_QUEUED
852 +
853 1 *
854 VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
855 NULL);
856 } else {
857 while (count > 0) {
858 int bytes = min((int) m.u.write.max_packet, (int) count);
859
860 status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
861 src, bytes);
862 src = (char *)src + bytes;
863 count -= bytes;
864 }
865 }
866 if (status) {
867 LOG_ERR("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
868 __func__, status);
869
870 ret = -1;
871 goto unlock;
872 }
873 }
874 ret = 0;
875
876 unlock:
877 vchi_service_release(instance->vchi_handle[0]);
878 mutex_unlock(&instance->vchi_mutex);
879 LOG_DBG(" .. OUT\n");
880 return ret;
881 }
882
883 /**
884 * Returns all buffers from arm->vc
885 */
886 void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream)
887 {
888 LOG_DBG(" .. IN\n");
889 LOG_DBG(" .. OUT\n");
890 return;
891 }
892
893 /**
894 * Forces VC to flush(drop) its filled playback buffers and
895 * return them the us. (VC->ARM)
896 */
897 void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream)
898 {
899 LOG_DBG(" .. IN\n");
900 LOG_DBG(" .. OUT\n");
901 }
902
903 unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
904 {
905 unsigned int count = atomic_read(&alsa_stream->retrieved);
906
907 atomic_sub(count, &alsa_stream->retrieved);
908 return count;
909 }
910
911 module_param(force_bulk, bool, 0444);
912 MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");