linux/sound/core/compress_offload.c
<<
>>
Prefs
   1/*
   2 *  compress_core.c - compress offload core
   3 *
   4 *  Copyright (C) 2011 Intel Corporation
   5 *  Authors:    Vinod Koul <vinod.koul@linux.intel.com>
   6 *              Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
   7 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License as published by
  11 *  the Free Software Foundation; version 2 of the License.
  12 *
  13 *  This program is distributed in the hope that it will be useful, but
  14 *  WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16 *  General Public License for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License along
  19 *  with this program; if not, write to the Free Software Foundation, Inc.,
  20 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  21 *
  22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  23 *
  24 */
  25#define FORMAT(fmt) "%s: %d: " fmt, __func__, __LINE__
  26#define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
  27
  28#include <linux/file.h>
  29#include <linux/fs.h>
  30#include <linux/list.h>
  31#include <linux/math64.h>
  32#include <linux/mm.h>
  33#include <linux/mutex.h>
  34#include <linux/poll.h>
  35#include <linux/slab.h>
  36#include <linux/sched.h>
  37#include <linux/types.h>
  38#include <linux/uio.h>
  39#include <linux/uaccess.h>
  40#include <linux/module.h>
  41#include <sound/core.h>
  42#include <sound/initval.h>
  43#include <sound/compress_params.h>
  44#include <sound/compress_offload.h>
  45#include <sound/compress_driver.h>
  46
  47/* TODO:
  48 * - add substream support for multiple devices in case of
  49 *      SND_DYNAMIC_MINORS is not used
  50 * - Multiple node representation
  51 *      driver should be able to register multiple nodes
  52 */
  53
  54static DEFINE_MUTEX(device_mutex);
  55
  56struct snd_compr_file {
  57        unsigned long caps;
  58        struct snd_compr_stream stream;
  59};
  60
  61/*
  62 * a note on stream states used:
  63 * we use follwing states in the compressed core
  64 * SNDRV_PCM_STATE_OPEN: When stream has been opened.
  65 * SNDRV_PCM_STATE_SETUP: When stream has been initialized. This is done by
  66 *      calling SNDRV_COMPRESS_SET_PARAMS. running streams will come to this
  67 *      state at stop by calling SNDRV_COMPRESS_STOP, or at end of drain.
  68 * SNDRV_PCM_STATE_RUNNING: When stream has been started and is
  69 *      decoding/encoding and rendering/capturing data.
  70 * SNDRV_PCM_STATE_DRAINING: When stream is draining current data. This is done
  71 *      by calling SNDRV_COMPRESS_DRAIN.
  72 * SNDRV_PCM_STATE_PAUSED: When stream is paused. This is done by calling
  73 *      SNDRV_COMPRESS_PAUSE. It can be stopped or resumed by calling
  74 *      SNDRV_COMPRESS_STOP or SNDRV_COMPRESS_RESUME respectively.
  75 */
  76static int snd_compr_open(struct inode *inode, struct file *f)
  77{
  78        struct snd_compr *compr;
  79        struct snd_compr_file *data;
  80        struct snd_compr_runtime *runtime;
  81        enum snd_compr_direction dirn;
  82        int maj = imajor(inode);
  83        int ret;
  84
  85        if ((f->f_flags & O_ACCMODE) == O_WRONLY)
  86                dirn = SND_COMPRESS_PLAYBACK;
  87        else if ((f->f_flags & O_ACCMODE) == O_RDONLY)
  88                dirn = SND_COMPRESS_CAPTURE;
  89        else
  90                return -EINVAL;
  91
  92        if (maj == snd_major)
  93                compr = snd_lookup_minor_data(iminor(inode),
  94                                        SNDRV_DEVICE_TYPE_COMPRESS);
  95        else
  96                return -EBADFD;
  97
  98        if (compr == NULL) {
  99                pr_err("no device data!!!\n");
 100                return -ENODEV;
 101        }
 102
 103        if (dirn != compr->direction) {
 104                pr_err("this device doesn't support this direction\n");
 105                snd_card_unref(compr->card);
 106                return -EINVAL;
 107        }
 108
 109        data = kzalloc(sizeof(*data), GFP_KERNEL);
 110        if (!data) {
 111                snd_card_unref(compr->card);
 112                return -ENOMEM;
 113        }
 114        data->stream.ops = compr->ops;
 115        data->stream.direction = dirn;
 116        data->stream.private_data = compr->private_data;
 117        data->stream.device = compr;
 118        runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
 119        if (!runtime) {
 120                kfree(data);
 121                snd_card_unref(compr->card);
 122                return -ENOMEM;
 123        }
 124        runtime->state = SNDRV_PCM_STATE_OPEN;
 125        init_waitqueue_head(&runtime->sleep);
 126        data->stream.runtime = runtime;
 127        f->private_data = (void *)data;
 128        mutex_lock(&compr->lock);
 129        ret = compr->ops->open(&data->stream);
 130        mutex_unlock(&compr->lock);
 131        if (ret) {
 132                kfree(runtime);
 133                kfree(data);
 134        }
 135        snd_card_unref(compr->card);
 136        return 0;
 137}
 138
 139static int snd_compr_free(struct inode *inode, struct file *f)
 140{
 141        struct snd_compr_file *data = f->private_data;
 142        data->stream.ops->free(&data->stream);
 143        kfree(data->stream.runtime->buffer);
 144        kfree(data->stream.runtime);
 145        kfree(data);
 146        return 0;
 147}
 148
 149static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
 150                struct snd_compr_tstamp *tstamp)
 151{
 152        if (!stream->ops->pointer)
 153                return -ENOTSUPP;
 154        stream->ops->pointer(stream, tstamp);
 155        pr_debug("dsp consumed till %d total %d bytes\n",
 156                tstamp->byte_offset, tstamp->copied_total);
 157        if (stream->direction == SND_COMPRESS_PLAYBACK)
 158                stream->runtime->total_bytes_transferred = tstamp->copied_total;
 159        else
 160                stream->runtime->total_bytes_available = tstamp->copied_total;
 161        return 0;
 162}
 163
 164static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
 165                struct snd_compr_avail *avail)
 166{
 167        memset(avail, 0, sizeof(*avail));
 168        snd_compr_update_tstamp(stream, &avail->tstamp);
 169        /* Still need to return avail even if tstamp can't be filled in */
 170
 171        if (stream->runtime->total_bytes_available == 0 &&
 172                        stream->runtime->state == SNDRV_PCM_STATE_SETUP &&
 173                        stream->direction == SND_COMPRESS_PLAYBACK) {
 174                pr_debug("detected init and someone forgot to do a write\n");
 175                return stream->runtime->buffer_size;
 176        }
 177        pr_debug("app wrote %lld, DSP consumed %lld\n",
 178                        stream->runtime->total_bytes_available,
 179                        stream->runtime->total_bytes_transferred);
 180        if (stream->runtime->total_bytes_available ==
 181                                stream->runtime->total_bytes_transferred) {
 182                if (stream->direction == SND_COMPRESS_PLAYBACK) {
 183                        pr_debug("both pointers are same, returning full avail\n");
 184                        return stream->runtime->buffer_size;
 185                } else {
 186                        pr_debug("both pointers are same, returning no avail\n");
 187                        return 0;
 188                }
 189        }
 190
 191        avail->avail = stream->runtime->total_bytes_available -
 192                        stream->runtime->total_bytes_transferred;
 193        if (stream->direction == SND_COMPRESS_PLAYBACK)
 194                avail->avail = stream->runtime->buffer_size - avail->avail;
 195
 196        pr_debug("ret avail as %lld\n", avail->avail);
 197        return avail->avail;
 198}
 199
 200static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream)
 201{
 202        struct snd_compr_avail avail;
 203
 204        return snd_compr_calc_avail(stream, &avail);
 205}
 206
 207static int
 208snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
 209{
 210        struct snd_compr_avail ioctl_avail;
 211        size_t avail;
 212
 213        avail = snd_compr_calc_avail(stream, &ioctl_avail);
 214        ioctl_avail.avail = avail;
 215
 216        if (copy_to_user((__u64 __user *)arg,
 217                                &ioctl_avail, sizeof(ioctl_avail)))
 218                return -EFAULT;
 219        return 0;
 220}
 221
 222static int snd_compr_write_data(struct snd_compr_stream *stream,
 223               const char __user *buf, size_t count)
 224{
 225        void *dstn;
 226        size_t copy;
 227        struct snd_compr_runtime *runtime = stream->runtime;
 228        /* 64-bit Modulus */
 229        u64 app_pointer = div64_u64(runtime->total_bytes_available,
 230                                    runtime->buffer_size);
 231        app_pointer = runtime->total_bytes_available -
 232                      (app_pointer * runtime->buffer_size);
 233
 234        dstn = runtime->buffer + app_pointer;
 235        pr_debug("copying %ld at %lld\n",
 236                        (unsigned long)count, app_pointer);
 237        if (count < runtime->buffer_size - app_pointer) {
 238                if (copy_from_user(dstn, buf, count))
 239                        return -EFAULT;
 240        } else {
 241                copy = runtime->buffer_size - app_pointer;
 242                if (copy_from_user(dstn, buf, copy))
 243                        return -EFAULT;
 244                if (copy_from_user(runtime->buffer, buf + copy, count - copy))
 245                        return -EFAULT;
 246        }
 247        /* if DSP cares, let it know data has been written */
 248        if (stream->ops->ack)
 249                stream->ops->ack(stream, count);
 250        return count;
 251}
 252
 253static ssize_t snd_compr_write(struct file *f, const char __user *buf,
 254                size_t count, loff_t *offset)
 255{
 256        struct snd_compr_file *data = f->private_data;
 257        struct snd_compr_stream *stream;
 258        size_t avail;
 259        int retval;
 260
 261        if (snd_BUG_ON(!data))
 262                return -EFAULT;
 263
 264        stream = &data->stream;
 265        mutex_lock(&stream->device->lock);
 266        /* write is allowed when stream is running or has been steup */
 267        if (stream->runtime->state != SNDRV_PCM_STATE_SETUP &&
 268                        stream->runtime->state != SNDRV_PCM_STATE_RUNNING) {
 269                mutex_unlock(&stream->device->lock);
 270                return -EBADFD;
 271        }
 272
 273        avail = snd_compr_get_avail(stream);
 274        pr_debug("avail returned %ld\n", (unsigned long)avail);
 275        /* calculate how much we can write to buffer */
 276        if (avail > count)
 277                avail = count;
 278
 279        if (stream->ops->copy) {
 280                char __user* cbuf = (char __user*)buf;
 281                retval = stream->ops->copy(stream, cbuf, avail);
 282        } else {
 283                retval = snd_compr_write_data(stream, buf, avail);
 284        }
 285        if (retval > 0)
 286                stream->runtime->total_bytes_available += retval;
 287
 288        /* while initiating the stream, write should be called before START
 289         * call, so in setup move state */
 290        if (stream->runtime->state == SNDRV_PCM_STATE_SETUP) {
 291                stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
 292                pr_debug("stream prepared, Houston we are good to go\n");
 293        }
 294
 295        mutex_unlock(&stream->device->lock);
 296        return retval;
 297}
 298
 299
 300static ssize_t snd_compr_read(struct file *f, char __user *buf,
 301                size_t count, loff_t *offset)
 302{
 303        struct snd_compr_file *data = f->private_data;
 304        struct snd_compr_stream *stream;
 305        size_t avail;
 306        int retval;
 307
 308        if (snd_BUG_ON(!data))
 309                return -EFAULT;
 310
 311        stream = &data->stream;
 312        mutex_lock(&stream->device->lock);
 313
 314        /* read is allowed when stream is running, paused, draining and setup
 315         * (yes setup is state which we transition to after stop, so if user
 316         * wants to read data after stop we allow that)
 317         */
 318        switch (stream->runtime->state) {
 319        case SNDRV_PCM_STATE_OPEN:
 320        case SNDRV_PCM_STATE_PREPARED:
 321        case SNDRV_PCM_STATE_XRUN:
 322        case SNDRV_PCM_STATE_SUSPENDED:
 323        case SNDRV_PCM_STATE_DISCONNECTED:
 324                retval = -EBADFD;
 325                goto out;
 326        }
 327
 328        avail = snd_compr_get_avail(stream);
 329        pr_debug("avail returned %ld\n", (unsigned long)avail);
 330        /* calculate how much we can read from buffer */
 331        if (avail > count)
 332                avail = count;
 333
 334        if (stream->ops->copy) {
 335                retval = stream->ops->copy(stream, buf, avail);
 336        } else {
 337                retval = -ENXIO;
 338                goto out;
 339        }
 340        if (retval > 0)
 341                stream->runtime->total_bytes_transferred += retval;
 342
 343out:
 344        mutex_unlock(&stream->device->lock);
 345        return retval;
 346}
 347
 348static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma)
 349{
 350        return -ENXIO;
 351}
 352
 353static inline int snd_compr_get_poll(struct snd_compr_stream *stream)
 354{
 355        if (stream->direction == SND_COMPRESS_PLAYBACK)
 356                return POLLOUT | POLLWRNORM;
 357        else
 358                return POLLIN | POLLRDNORM;
 359}
 360
 361static unsigned int snd_compr_poll(struct file *f, poll_table *wait)
 362{
 363        struct snd_compr_file *data = f->private_data;
 364        struct snd_compr_stream *stream;
 365        size_t avail;
 366        int retval = 0;
 367
 368        if (snd_BUG_ON(!data))
 369                return -EFAULT;
 370        stream = &data->stream;
 371        if (snd_BUG_ON(!stream))
 372                return -EFAULT;
 373
 374        mutex_lock(&stream->device->lock);
 375        if (stream->runtime->state == SNDRV_PCM_STATE_PAUSED ||
 376                        stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
 377                retval = -EBADFD;
 378                goto out;
 379        }
 380        poll_wait(f, &stream->runtime->sleep, wait);
 381
 382        avail = snd_compr_get_avail(stream);
 383        pr_debug("avail is %ld\n", (unsigned long)avail);
 384        /* check if we have at least one fragment to fill */
 385        switch (stream->runtime->state) {
 386        case SNDRV_PCM_STATE_DRAINING:
 387                /* stream has been woken up after drain is complete
 388                 * draining done so set stream state to stopped
 389                 */
 390                retval = snd_compr_get_poll(stream);
 391                stream->runtime->state = SNDRV_PCM_STATE_SETUP;
 392                break;
 393        case SNDRV_PCM_STATE_RUNNING:
 394        case SNDRV_PCM_STATE_PREPARED:
 395        case SNDRV_PCM_STATE_PAUSED:
 396                if (avail >= stream->runtime->fragment_size)
 397                        retval = snd_compr_get_poll(stream);
 398                break;
 399        default:
 400                if (stream->direction == SND_COMPRESS_PLAYBACK)
 401                        retval = POLLOUT | POLLWRNORM | POLLERR;
 402                else
 403                        retval = POLLIN | POLLRDNORM | POLLERR;
 404                break;
 405        }
 406out:
 407        mutex_unlock(&stream->device->lock);
 408        return retval;
 409}
 410
 411static int
 412snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg)
 413{
 414        int retval;
 415        struct snd_compr_caps caps;
 416
 417        if (!stream->ops->get_caps)
 418                return -ENXIO;
 419
 420        memset(&caps, 0, sizeof(caps));
 421        retval = stream->ops->get_caps(stream, &caps);
 422        if (retval)
 423                goto out;
 424        if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
 425                retval = -EFAULT;
 426out:
 427        return retval;
 428}
 429
 430static int
 431snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
 432{
 433        int retval;
 434        struct snd_compr_codec_caps *caps;
 435
 436        if (!stream->ops->get_codec_caps)
 437                return -ENXIO;
 438
 439        caps = kzalloc(sizeof(*caps), GFP_KERNEL);
 440        if (!caps)
 441                return -ENOMEM;
 442
 443        retval = stream->ops->get_codec_caps(stream, caps);
 444        if (retval)
 445                goto out;
 446        if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
 447                retval = -EFAULT;
 448
 449out:
 450        kfree(caps);
 451        return retval;
 452}
 453
 454/* revisit this with snd_pcm_preallocate_xxx */
 455static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
 456                struct snd_compr_params *params)
 457{
 458        unsigned int buffer_size;
 459        void *buffer;
 460
 461        buffer_size = params->buffer.fragment_size * params->buffer.fragments;
 462        if (stream->ops->copy) {
 463                buffer = NULL;
 464                /* if copy is defined the driver will be required to copy
 465                 * the data from core
 466                 */
 467        } else {
 468                buffer = kmalloc(buffer_size, GFP_KERNEL);
 469                if (!buffer)
 470                        return -ENOMEM;
 471        }
 472        stream->runtime->fragment_size = params->buffer.fragment_size;
 473        stream->runtime->fragments = params->buffer.fragments;
 474        stream->runtime->buffer = buffer;
 475        stream->runtime->buffer_size = buffer_size;
 476        return 0;
 477}
 478
 479static int snd_compress_check_input(struct snd_compr_params *params)
 480{
 481        /* first let's check the buffer parameter's */
 482        if (params->buffer.fragment_size == 0 ||
 483                        params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size)
 484                return -EINVAL;
 485
 486        /* now codec parameters */
 487        if (params->codec.id == 0 || params->codec.id > SND_AUDIOCODEC_MAX)
 488                return -EINVAL;
 489
 490        if (params->codec.ch_in == 0 || params->codec.ch_out == 0)
 491                return -EINVAL;
 492
 493        if (!(params->codec.sample_rate & SNDRV_PCM_RATE_8000_192000))
 494                return -EINVAL;
 495
 496        return 0;
 497}
 498
 499static int
 500snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
 501{
 502        struct snd_compr_params *params;
 503        int retval;
 504
 505        if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
 506                /*
 507                 * we should allow parameter change only when stream has been
 508                 * opened not in other cases
 509                 */
 510                params = kmalloc(sizeof(*params), GFP_KERNEL);
 511                if (!params)
 512                        return -ENOMEM;
 513                if (copy_from_user(params, (void __user *)arg, sizeof(*params))) {
 514                        retval = -EFAULT;
 515                        goto out;
 516                }
 517
 518                retval = snd_compress_check_input(params);
 519                if (retval)
 520                        goto out;
 521
 522                retval = snd_compr_allocate_buffer(stream, params);
 523                if (retval) {
 524                        retval = -ENOMEM;
 525                        goto out;
 526                }
 527
 528                retval = stream->ops->set_params(stream, params);
 529                if (retval)
 530                        goto out;
 531
 532                stream->metadata_set = false;
 533                stream->next_track = false;
 534
 535                if (stream->direction == SND_COMPRESS_PLAYBACK)
 536                        stream->runtime->state = SNDRV_PCM_STATE_SETUP;
 537                else
 538                        stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
 539        } else {
 540                return -EPERM;
 541        }
 542out:
 543        kfree(params);
 544        return retval;
 545}
 546
 547static int
 548snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
 549{
 550        struct snd_codec *params;
 551        int retval;
 552
 553        if (!stream->ops->get_params)
 554                return -EBADFD;
 555
 556        params = kzalloc(sizeof(*params), GFP_KERNEL);
 557        if (!params)
 558                return -ENOMEM;
 559        retval = stream->ops->get_params(stream, params);
 560        if (retval)
 561                goto out;
 562        if (copy_to_user((char __user *)arg, params, sizeof(*params)))
 563                retval = -EFAULT;
 564
 565out:
 566        kfree(params);
 567        return retval;
 568}
 569
 570static int
 571snd_compr_get_metadata(struct snd_compr_stream *stream, unsigned long arg)
 572{
 573        struct snd_compr_metadata metadata;
 574        int retval;
 575
 576        if (!stream->ops->get_metadata)
 577                return -ENXIO;
 578
 579        if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
 580                return -EFAULT;
 581
 582        retval = stream->ops->get_metadata(stream, &metadata);
 583        if (retval != 0)
 584                return retval;
 585
 586        if (copy_to_user((void __user *)arg, &metadata, sizeof(metadata)))
 587                return -EFAULT;
 588
 589        return 0;
 590}
 591
 592static int
 593snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg)
 594{
 595        struct snd_compr_metadata metadata;
 596        int retval;
 597
 598        if (!stream->ops->set_metadata)
 599                return -ENXIO;
 600        /*
 601        * we should allow parameter change only when stream has been
 602        * opened not in other cases
 603        */
 604        if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
 605                return -EFAULT;
 606
 607        retval = stream->ops->set_metadata(stream, &metadata);
 608        stream->metadata_set = true;
 609
 610        return retval;
 611}
 612
 613static inline int
 614snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
 615{
 616        struct snd_compr_tstamp tstamp = {0};
 617        int ret;
 618
 619        ret = snd_compr_update_tstamp(stream, &tstamp);
 620        if (ret == 0)
 621                ret = copy_to_user((struct snd_compr_tstamp __user *)arg,
 622                        &tstamp, sizeof(tstamp)) ? -EFAULT : 0;
 623        return ret;
 624}
 625
 626static int snd_compr_pause(struct snd_compr_stream *stream)
 627{
 628        int retval;
 629
 630        if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
 631                return -EPERM;
 632        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
 633        if (!retval)
 634                stream->runtime->state = SNDRV_PCM_STATE_PAUSED;
 635        return retval;
 636}
 637
 638static int snd_compr_resume(struct snd_compr_stream *stream)
 639{
 640        int retval;
 641
 642        if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED)
 643                return -EPERM;
 644        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
 645        if (!retval)
 646                stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
 647        return retval;
 648}
 649
 650static int snd_compr_start(struct snd_compr_stream *stream)
 651{
 652        int retval;
 653
 654        if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
 655                return -EPERM;
 656        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);
 657        if (!retval)
 658                stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
 659        return retval;
 660}
 661
 662static int snd_compr_stop(struct snd_compr_stream *stream)
 663{
 664        int retval;
 665
 666        if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
 667                        stream->runtime->state == SNDRV_PCM_STATE_SETUP)
 668                return -EPERM;
 669        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
 670        if (!retval) {
 671                stream->runtime->state = SNDRV_PCM_STATE_SETUP;
 672                wake_up(&stream->runtime->sleep);
 673                stream->runtime->total_bytes_available = 0;
 674                stream->runtime->total_bytes_transferred = 0;
 675        }
 676        return retval;
 677}
 678
 679static int snd_compr_drain(struct snd_compr_stream *stream)
 680{
 681        int retval;
 682
 683        if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
 684                        stream->runtime->state == SNDRV_PCM_STATE_SETUP)
 685                return -EPERM;
 686        retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
 687        if (!retval) {
 688                stream->runtime->state = SNDRV_PCM_STATE_DRAINING;
 689                wake_up(&stream->runtime->sleep);
 690        }
 691        return retval;
 692}
 693
 694static int snd_compr_next_track(struct snd_compr_stream *stream)
 695{
 696        int retval;
 697
 698        /* only a running stream can transition to next track */
 699        if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
 700                return -EPERM;
 701
 702        /* you can signal next track isf this is intended to be a gapless stream
 703         * and current track metadata is set
 704         */
 705        if (stream->metadata_set == false)
 706                return -EPERM;
 707
 708        retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_NEXT_TRACK);
 709        if (retval != 0)
 710                return retval;
 711        stream->metadata_set = false;
 712        stream->next_track = true;
 713        return 0;
 714}
 715
 716static int snd_compr_partial_drain(struct snd_compr_stream *stream)
 717{
 718        int retval;
 719        if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
 720                        stream->runtime->state == SNDRV_PCM_STATE_SETUP)
 721                return -EPERM;
 722        /* stream can be drained only when next track has been signalled */
 723        if (stream->next_track == false)
 724                return -EPERM;
 725
 726        retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);
 727
 728        stream->next_track = false;
 729        return retval;
 730}
 731
 732static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
 733{
 734        struct snd_compr_file *data = f->private_data;
 735        struct snd_compr_stream *stream;
 736        int retval = -ENOTTY;
 737
 738        if (snd_BUG_ON(!data))
 739                return -EFAULT;
 740        stream = &data->stream;
 741        if (snd_BUG_ON(!stream))
 742                return -EFAULT;
 743        mutex_lock(&stream->device->lock);
 744        switch (_IOC_NR(cmd)) {
 745        case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
 746                put_user(SNDRV_COMPRESS_VERSION,
 747                                (int __user *)arg) ? -EFAULT : 0;
 748                break;
 749        case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
 750                retval = snd_compr_get_caps(stream, arg);
 751                break;
 752        case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
 753                retval = snd_compr_get_codec_caps(stream, arg);
 754                break;
 755        case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
 756                retval = snd_compr_set_params(stream, arg);
 757                break;
 758        case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
 759                retval = snd_compr_get_params(stream, arg);
 760                break;
 761        case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):
 762                retval = snd_compr_set_metadata(stream, arg);
 763                break;
 764        case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
 765                retval = snd_compr_get_metadata(stream, arg);
 766                break;
 767        case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
 768                retval = snd_compr_tstamp(stream, arg);
 769                break;
 770        case _IOC_NR(SNDRV_COMPRESS_AVAIL):
 771                retval = snd_compr_ioctl_avail(stream, arg);
 772                break;
 773        case _IOC_NR(SNDRV_COMPRESS_PAUSE):
 774                retval = snd_compr_pause(stream);
 775                break;
 776        case _IOC_NR(SNDRV_COMPRESS_RESUME):
 777                retval = snd_compr_resume(stream);
 778                break;
 779        case _IOC_NR(SNDRV_COMPRESS_START):
 780                retval = snd_compr_start(stream);
 781                break;
 782        case _IOC_NR(SNDRV_COMPRESS_STOP):
 783                retval = snd_compr_stop(stream);
 784                break;
 785        case _IOC_NR(SNDRV_COMPRESS_DRAIN):
 786                retval = snd_compr_drain(stream);
 787                break;
 788        case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):
 789                retval = snd_compr_partial_drain(stream);
 790                break;
 791        case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):
 792                retval = snd_compr_next_track(stream);
 793                break;
 794
 795        }
 796        mutex_unlock(&stream->device->lock);
 797        return retval;
 798}
 799
 800static const struct file_operations snd_compr_file_ops = {
 801                .owner =        THIS_MODULE,
 802                .open =         snd_compr_open,
 803                .release =      snd_compr_free,
 804                .write =        snd_compr_write,
 805                .read =         snd_compr_read,
 806                .unlocked_ioctl = snd_compr_ioctl,
 807                .mmap =         snd_compr_mmap,
 808                .poll =         snd_compr_poll,
 809};
 810
 811static int snd_compress_dev_register(struct snd_device *device)
 812{
 813        int ret = -EINVAL;
 814        char str[16];
 815        struct snd_compr *compr;
 816
 817        if (snd_BUG_ON(!device || !device->device_data))
 818                return -EBADFD;
 819        compr = device->device_data;
 820
 821        sprintf(str, "comprC%iD%i", compr->card->number, compr->device);
 822        pr_debug("reg %s for device %s, direction %d\n", str, compr->name,
 823                        compr->direction);
 824        /* register compressed device */
 825        ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
 826                        compr->device, &snd_compr_file_ops, compr, str);
 827        if (ret < 0) {
 828                pr_err("snd_register_device failed\n %d", ret);
 829                return ret;
 830        }
 831        return ret;
 832
 833}
 834
 835static int snd_compress_dev_disconnect(struct snd_device *device)
 836{
 837        struct snd_compr *compr;
 838
 839        compr = device->device_data;
 840        snd_unregister_device(compr->direction, compr->card, compr->device);
 841        return 0;
 842}
 843
 844/*
 845 * snd_compress_new: create new compress device
 846 * @card: sound card pointer
 847 * @device: device number
 848 * @dirn: device direction, should be of type enum snd_compr_direction
 849 * @compr: compress device pointer
 850 */
 851int snd_compress_new(struct snd_card *card, int device,
 852                        int dirn, struct snd_compr *compr)
 853{
 854        static struct snd_device_ops ops = {
 855                .dev_free = NULL,
 856                .dev_register = snd_compress_dev_register,
 857                .dev_disconnect = snd_compress_dev_disconnect,
 858        };
 859
 860        compr->card = card;
 861        compr->device = device;
 862        compr->direction = dirn;
 863        return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
 864}
 865EXPORT_SYMBOL_GPL(snd_compress_new);
 866
 867static int snd_compress_add_device(struct snd_compr *device)
 868{
 869        int ret;
 870
 871        if (!device->card)
 872                return -EINVAL;
 873
 874        /* register the card */
 875        ret = snd_card_register(device->card);
 876        if (ret)
 877                goto out;
 878        return 0;
 879
 880out:
 881        pr_err("failed with %d\n", ret);
 882        return ret;
 883
 884}
 885
 886static int snd_compress_remove_device(struct snd_compr *device)
 887{
 888        return snd_card_free(device->card);
 889}
 890
 891/**
 892 * snd_compress_register - register compressed device
 893 *
 894 * @device: compressed device to register
 895 */
 896int snd_compress_register(struct snd_compr *device)
 897{
 898        int retval;
 899
 900        if (device->name == NULL || device->dev == NULL || device->ops == NULL)
 901                return -EINVAL;
 902
 903        pr_debug("Registering compressed device %s\n", device->name);
 904        if (snd_BUG_ON(!device->ops->open))
 905                return -EINVAL;
 906        if (snd_BUG_ON(!device->ops->free))
 907                return -EINVAL;
 908        if (snd_BUG_ON(!device->ops->set_params))
 909                return -EINVAL;
 910        if (snd_BUG_ON(!device->ops->trigger))
 911                return -EINVAL;
 912
 913        mutex_init(&device->lock);
 914
 915        /* register a compressed card */
 916        mutex_lock(&device_mutex);
 917        retval = snd_compress_add_device(device);
 918        mutex_unlock(&device_mutex);
 919        return retval;
 920}
 921EXPORT_SYMBOL_GPL(snd_compress_register);
 922
 923int snd_compress_deregister(struct snd_compr *device)
 924{
 925        pr_debug("Removing compressed device %s\n", device->name);
 926        mutex_lock(&device_mutex);
 927        snd_compress_remove_device(device);
 928        mutex_unlock(&device_mutex);
 929        return 0;
 930}
 931EXPORT_SYMBOL_GPL(snd_compress_deregister);
 932
 933static int __init snd_compress_init(void)
 934{
 935        return 0;
 936}
 937
 938static void __exit snd_compress_exit(void)
 939{
 940}
 941
 942module_init(snd_compress_init);
 943module_exit(snd_compress_exit);
 944
 945MODULE_DESCRIPTION("ALSA Compressed offload framework");
 946MODULE_AUTHOR("Vinod Koul <vinod.koul@linux.intel.com>");
 947MODULE_LICENSE("GPL v2");
 948