root/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bcm2835_audio_lock
  2. bcm2835_audio_unlock
  3. bcm2835_audio_send_msg_locked
  4. bcm2835_audio_send_msg
  5. bcm2835_audio_send_simple
  6. audio_vchi_callback
  7. vc_vchi_audio_init
  8. vc_vchi_audio_deinit
  9. bcm2835_new_vchi_ctx
  10. bcm2835_free_vchi_ctx
  11. bcm2835_audio_open
  12. bcm2835_audio_set_ctls
  13. bcm2835_audio_set_params
  14. bcm2835_audio_start
  15. bcm2835_audio_stop
  16. bcm2835_audio_drain
  17. bcm2835_audio_close
  18. bcm2835_audio_write

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* Copyright 2011 Broadcom Corporation.  All rights reserved. */
   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         /* Open the VCHI service connections */
 134         status = vchi_service_open(vchi_instance, &params,
 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         /* Finished with the service for now */
 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         /* Close all VCHI service connections */
 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         /* Initialize and create a VCHI connection */
 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         /* Close the VCHI connection - it will also free vchi_instance */
 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         /* Allocate memory for this instance */
 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; /* bulk transfer */
 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         /* resend ctls - alsa_stream may not have been open when first send */
 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 /* FIXME: this doesn't seem working as expected for "draining" */
 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         /* Stop the audio service */
 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                 /* Send the message to the videocore */
 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 }

/* [<][>][^][v][top][bottom][index][help] */