1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2011 Broadcom Corporation. All rights reserved. */
4 #include <linux/device.h>
5 #include <sound/core.h>
6 #include <sound/initval.h>
9 #include <linux/interrupt.h>
11 #include <linux/file.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>
23 /* ---- Include Files -------------------------------------------------------- */
25 #include "vc_vchi_audioserv_defs.h"
27 /* ---- Private Constants and Types ------------------------------------------ */
29 #define BCM2835_AUDIO_STOP 0
30 #define BCM2835_AUDIO_START 1
31 #define BCM2835_AUDIO_WRITE 2
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)
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)
46 struct bcm2835_audio_instance {
47 VCHI_SERVICE_HANDLE_T vchi_handle;
48 struct completion msg_avail_comp;
49 struct mutex vchi_mutex;
50 struct bcm2835_alsa_stream *alsa_stream;
52 unsigned int max_packet;
56 static bool force_bulk;
58 /* ---- Private Variables ---------------------------------------------------- */
60 /* ---- Private Function Prototypes ------------------------------------------ */
62 /* ---- Private Functions ---------------------------------------------------- */
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);
69 static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
71 mutex_lock(&instance->vchi_mutex);
72 vchi_service_use(instance->vchi_handle);
75 static void bcm2835_audio_unlock(struct bcm2835_audio_instance *instance)
77 vchi_service_release(instance->vchi_handle);
78 mutex_unlock(&instance->vchi_mutex);
81 static int bcm2835_audio_send_msg_locked(struct bcm2835_audio_instance *instance,
82 struct vc_audio_msg *m, bool wait)
87 instance->result = -1;
88 init_completion(&instance->msg_avail_comp);
91 status = vchi_queue_kernel_message(instance->vchi_handle,
94 LOG_ERR("vchi message queue failed: %d, msg=%d\n",
100 if (!wait_for_completion_timeout(&instance->msg_avail_comp,
101 msecs_to_jiffies(10 * 1000))) {
102 LOG_ERR("vchi message timeout, msg=%d\n", m->type);
104 } else if (instance->result) {
105 LOG_ERR("vchi message response error:%d, msg=%d\n",
106 instance->result, m->type);
114 static int bcm2835_audio_send_msg(struct bcm2835_audio_instance *instance,
115 struct vc_audio_msg *m, bool wait)
119 bcm2835_audio_lock(instance);
120 err = bcm2835_audio_send_msg_locked(instance, m, wait);
121 bcm2835_audio_unlock(instance);
125 static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance,
128 struct vc_audio_msg m = { .type = type };
130 return bcm2835_audio_send_msg(instance, &m, wait);
133 static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 |
135 static const u32 BCM2835_AUDIO_WRITE_COOKIE2 = ('D' << 24 | 'A' << 16 |
138 struct bcm2835_audio_work {
139 struct work_struct my_work;
140 struct bcm2835_alsa_stream *alsa_stream;
146 static void my_wq_function(struct work_struct *work)
148 struct bcm2835_audio_work *w =
149 container_of(work, struct bcm2835_audio_work, my_work);
153 case BCM2835_AUDIO_START:
154 ret = bcm2835_audio_start_worker(w->alsa_stream);
156 case BCM2835_AUDIO_STOP:
157 ret = bcm2835_audio_stop_worker(w->alsa_stream);
159 case BCM2835_AUDIO_WRITE:
160 ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
164 LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
170 int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
172 struct bcm2835_audio_work *work;
174 work = kmalloc(sizeof(*work), GFP_ATOMIC);
175 /*--- Queue some work (item 1) ---*/
177 LOG_ERR(" .. Error: NULL work kmalloc\n");
180 INIT_WORK(&work->my_work, my_wq_function);
181 work->alsa_stream = alsa_stream;
182 work->cmd = BCM2835_AUDIO_START;
183 if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
190 int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
192 struct bcm2835_audio_work *work;
194 work = kmalloc(sizeof(*work), GFP_ATOMIC);
195 /*--- Queue some work (item 1) ---*/
197 LOG_ERR(" .. Error: NULL work kmalloc\n");
200 INIT_WORK(&work->my_work, my_wq_function);
201 work->alsa_stream = alsa_stream;
202 work->cmd = BCM2835_AUDIO_STOP;
203 if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
210 int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
211 unsigned int count, void *src)
213 struct bcm2835_audio_work *work;
215 work = kmalloc(sizeof(*work), GFP_ATOMIC);
216 /*--- Queue some work (item 1) ---*/
218 LOG_ERR(" .. Error: NULL work kmalloc\n");
221 INIT_WORK(&work->my_work, my_wq_function);
222 work->alsa_stream = alsa_stream;
223 work->cmd = BCM2835_AUDIO_WRITE;
226 if (!queue_work(alsa_stream->my_wq, &work->my_work)) {
233 static void my_workqueue_quit(struct bcm2835_alsa_stream *alsa_stream)
235 flush_workqueue(alsa_stream->my_wq);
236 destroy_workqueue(alsa_stream->my_wq);
237 alsa_stream->my_wq = NULL;
240 static void audio_vchi_callback(void *param,
241 const VCHI_CALLBACK_REASON_T reason,
244 struct bcm2835_audio_instance *instance = param;
247 struct vc_audio_msg m;
249 if (reason != VCHI_CALLBACK_MSG_AVAILABLE)
253 LOG_ERR(" .. instance is null\n");
257 if (!instance->vchi_handle) {
258 LOG_ERR(" .. instance->vchi_handle is null\n");
262 status = vchi_msg_dequeue(instance->vchi_handle,
263 &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
264 if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
265 LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
266 instance, m.u.result.success);
267 instance->result = m.u.result.success;
268 complete(&instance->msg_avail_comp);
269 } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
270 struct bcm2835_alsa_stream *alsa_stream = instance->alsa_stream;
272 LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
273 instance, m.u.complete.count);
274 if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
275 m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
276 LOG_ERR(" .. response is corrupt\n");
277 else if (alsa_stream) {
278 atomic_add(m.u.complete.count,
279 &alsa_stream->retrieved);
280 bcm2835_playback_fifo(alsa_stream);
282 LOG_ERR(" .. unexpected alsa_stream=%p\n",
286 LOG_ERR(" .. unexpected m.type=%d\n", m.type);
290 static struct bcm2835_audio_instance *
291 vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
292 VCHI_CONNECTION_T *vchi_connection)
294 SERVICE_CREATION_T params = {
295 .version = VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
296 .service_id = VC_AUDIO_SERVER_NAME,
297 .connection = vchi_connection,
300 .callback = audio_vchi_callback,
301 .want_unaligned_bulk_rx = 1, //TODO: remove VCOS_FALSE
302 .want_unaligned_bulk_tx = 1, //TODO: remove VCOS_FALSE
305 struct bcm2835_audio_instance *instance;
308 /* Allocate memory for this instance */
309 instance = kzalloc(sizeof(*instance), GFP_KERNEL);
311 return ERR_PTR(-ENOMEM);
313 /* Create a lock for exclusive, serialized VCHI connection access */
314 mutex_init(&instance->vchi_mutex);
315 /* Open the VCHI service connections */
316 params.callback_param = instance,
318 status = vchi_service_open(vchi_instance, ¶ms,
319 &instance->vchi_handle);
322 LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
325 return ERR_PTR(-EPERM);
328 /* Finished with the service for now */
329 vchi_service_release(instance->vchi_handle);
334 static int vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
338 mutex_lock(&instance->vchi_mutex);
339 vchi_service_use(instance->vchi_handle);
341 /* Close all VCHI service connections */
342 status = vchi_service_close(instance->vchi_handle);
344 LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
348 mutex_unlock(&instance->vchi_mutex);
355 int bcm2835_new_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
359 /* Initialize and create a VCHI connection */
360 ret = vchi_initialise(&vchi_ctx->vchi_instance);
362 LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
368 ret = vchi_connect(NULL, 0, vchi_ctx->vchi_instance);
370 LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
373 kfree(vchi_ctx->vchi_instance);
374 vchi_ctx->vchi_instance = NULL;
382 void bcm2835_free_vchi_ctx(struct bcm2835_vchi_ctx *vchi_ctx)
384 /* Close the VCHI connection - it will also free vchi_instance */
385 WARN_ON(vchi_disconnect(vchi_ctx->vchi_instance));
387 vchi_ctx->vchi_instance = NULL;
390 static int bcm2835_audio_open_connection(struct bcm2835_alsa_stream *alsa_stream)
392 struct bcm2835_audio_instance *instance =
393 (struct bcm2835_audio_instance *)alsa_stream->instance;
394 struct bcm2835_vchi_ctx *vhci_ctx = alsa_stream->chip->vchi_ctx;
396 /* Initialize an instance of the audio service */
397 instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
398 vhci_ctx->vchi_connection);
400 if (IS_ERR(instance))
401 return PTR_ERR(instance);
403 instance->alsa_stream = alsa_stream;
404 alsa_stream->instance = instance;
409 int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
411 struct bcm2835_audio_instance *instance;
414 alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
415 if (!alsa_stream->my_wq)
418 err = bcm2835_audio_open_connection(alsa_stream);
422 instance = alsa_stream->instance;
424 err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
429 bcm2835_audio_lock(instance);
430 vchi_get_peer_version(instance->vchi_handle, &instance->peer_version);
431 bcm2835_audio_unlock(instance);
432 if (instance->peer_version < 2 || force_bulk)
433 instance->max_packet = 0; /* bulk transfer */
435 instance->max_packet = 4000;
440 vc_vchi_audio_deinit(instance);
442 destroy_workqueue(alsa_stream->my_wq);
446 int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
448 struct bcm2835_chip *chip = alsa_stream->chip;
449 struct vc_audio_msg m = {};
451 m.type = VC_AUDIO_MSG_TYPE_CONTROL;
452 m.u.control.dest = chip->dest;
454 m.u.control.volume = CHIP_MIN_VOLUME;
456 m.u.control.volume = alsa2chip(chip->volume);
458 return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
461 int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
462 unsigned int channels, unsigned int samplerate,
465 struct vc_audio_msg m = {
466 .type = VC_AUDIO_MSG_TYPE_CONFIG,
467 .u.config.channels = channels,
468 .u.config.samplerate = samplerate,
473 /* resend ctls - alsa_stream may not have been open when first send */
474 err = bcm2835_audio_set_ctls(alsa_stream);
478 return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
481 static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
483 return bcm2835_audio_send_simple(alsa_stream->instance,
484 VC_AUDIO_MSG_TYPE_START, false);
487 static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
489 return bcm2835_audio_send_simple(alsa_stream->instance,
490 VC_AUDIO_MSG_TYPE_STOP, false);
493 int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
495 struct bcm2835_audio_instance *instance = alsa_stream->instance;
498 my_workqueue_quit(alsa_stream);
500 err = bcm2835_audio_send_simple(alsa_stream->instance,
501 VC_AUDIO_MSG_TYPE_CLOSE, true);
503 /* Stop the audio service */
504 vc_vchi_audio_deinit(instance);
505 alsa_stream->instance = NULL;
510 static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
511 unsigned int size, void *src)
513 struct bcm2835_audio_instance *instance = alsa_stream->instance;
514 struct vc_audio_msg m = {
515 .type = VC_AUDIO_MSG_TYPE_WRITE,
516 .u.write.count = size,
517 .u.write.max_packet = instance->max_packet,
518 .u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1,
519 .u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2,
527 bcm2835_audio_lock(instance);
528 err = bcm2835_audio_send_msg_locked(instance, &m, false);
533 if (!instance->max_packet) {
534 /* Send the message to the videocore */
535 status = vchi_bulk_queue_transmit(instance->vchi_handle,
537 VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
541 int bytes = min(instance->max_packet, count);
543 status = vchi_queue_kernel_message(instance->vchi_handle,
551 LOG_ERR("failed on %d bytes transfer (status=%d)\n",
557 bcm2835_audio_unlock(instance);
561 unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
563 unsigned int count = atomic_read(&alsa_stream->retrieved);
565 atomic_sub(count, &alsa_stream->retrieved);
569 module_param(force_bulk, bool, 0444);
570 MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");