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/mm.h>
  32#include <linux/mutex.h>
  33#include <linux/poll.h>
  34#include <linux/slab.h>
  35#include <linux/sched.h>
  36#include <linux/uio.h>
  37#include <linux/uaccess.h>
  38#include <linux/module.h>
  39#include <sound/core.h>
  40#include <sound/initval.h>
  41#include <sound/compress_params.h>
  42#include <sound/compress_offload.h>
  43#include <sound/compress_driver.h>
  44
  45/* TODO:
  46 * - add substream support for multiple devices in case of
  47 *      SND_DYNAMIC_MINORS is not used
  48 * - Multiple node representation
  49 *      driver should be able to register multiple nodes
  50 */
  51
  52static DEFINE_MUTEX(device_mutex);
  53
  54struct snd_compr_file {
  55        unsigned long caps;
  56        struct snd_compr_stream stream;
  57};
  58
  59/*
  60 * a note on stream states used:
  61 * we use follwing states in the compressed core
  62 * SNDRV_PCM_STATE_OPEN: When stream has been opened.
  63 * SNDRV_PCM_STATE_SETUP: When stream has been initialized. This is done by
  64 *      calling SNDRV_COMPRESS_SET_PARAMS. running streams will come to this
  65 *      state at stop by calling SNDRV_COMPRESS_STOP, or at end of drain.
  66 * SNDRV_PCM_STATE_RUNNING: When stream has been started and is
  67 *      decoding/encoding and rendering/capturing data.
  68 * SNDRV_PCM_STATE_DRAINING: When stream is draining current data. This is done
  69 *      by calling SNDRV_COMPRESS_DRAIN.
  70 * SNDRV_PCM_STATE_PAUSED: When stream is paused. This is done by calling
  71 *      SNDRV_COMPRESS_PAUSE. It can be stopped or resumed by calling
  72 *      SNDRV_COMPRESS_STOP or SNDRV_COMPRESS_RESUME respectively.
  73 */
  74static int snd_compr_open(struct inode *inode, struct file *f)
  75{
  76        struct snd_compr *compr;
  77        struct snd_compr_file *data;
  78        struct snd_compr_runtime *runtime;
  79        enum snd_compr_direction dirn;
  80        int maj = imajor(inode);
  81        int ret;
  82
  83        if ((f->f_flags & O_ACCMODE) == O_WRONLY)
  84                dirn = SND_COMPRESS_PLAYBACK;
  85        else if ((f->f_flags & O_ACCMODE) == O_RDONLY)
  86                dirn = SND_COMPRESS_CAPTURE;
  87        else
  88                return -EINVAL;
  89
  90        if (maj == snd_major)
  91                compr = snd_lookup_minor_data(iminor(inode),
  92                                        SNDRV_DEVICE_TYPE_COMPRESS);
  93        else
  94                return -EBADFD;
  95
  96        if (compr == NULL) {
  97                pr_err("no device data!!!\n");
  98                return -ENODEV;
  99        }
 100
 101        if (dirn != compr->direction) {
 102                pr_err("this device doesn't support this direction\n");
 103                snd_card_unref(compr->card);
 104                return -EINVAL;
 105        }
 106
 107        data = kzalloc(sizeof(*data), GFP_KERNEL);
 108        if (!data) {
 109                snd_card_unref(compr->card);
 110                return -ENOMEM;
 111        }
 112        data->stream.ops = compr->ops;
 113        data->stream.direction = dirn;
 114        data->stream.private_data = compr->private_data;
 115        data->stream.device = compr;
 116        runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
 117        if (!runtime) {
 118                kfree(data);
 119                snd_card_unref(compr->card);
 120                return -ENOMEM;
 121        }
 122        runtime->state = SNDRV_PCM_STATE_OPEN;
 123        init_waitqueue_head(&runtime->sleep);
 124        data->stream.runtime = runtime;
 125        f->private_data = (void *)data;
 126        mutex_lock(&compr->lock);
 127        ret = compr->ops->open(&data->stream);
 128        mutex_unlock(&compr->lock);
 129        if (ret) {
 130                kfree(runtime);
 131                kfree(data);
 132        }
 133        snd_card_unref(compr->card);
 134        return 0;
 135}
 136
 137static int snd_compr_free(struct inode *inode, struct file *f)
 138{
 139        struct snd_compr_file *data = f->private_data;
 140        data->stream.ops->free(&data->stream);
 141        kfree(data->stream.runtime->buffer);
 142        kfree(data->stream.runtime);
 143        kfree(data);
 144        return 0;
 145}
 146
 147static void snd_compr_update_tstamp(struct snd_compr_stream *stream,
 148                struct snd_compr_tstamp *tstamp)
 149{
 150        if (!stream->ops->pointer)
 151                return;
 152        stream->ops->pointer(stream, tstamp);
 153        pr_debug("dsp consumed till %d total %d bytes\n",
 154                tstamp->byte_offset, tstamp->copied_total);
 155        stream->runtime->hw_pointer = tstamp->byte_offset;
 156        stream->runtime->total_bytes_transferred = tstamp->copied_total;
 157}
 158
 159static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
 160                struct snd_compr_avail *avail)
 161{
 162        long avail_calc; /*this needs to be signed variable */
 163
 164        snd_compr_update_tstamp(stream, &avail->tstamp);
 165
 166        /* FIXME: This needs to be different for capture stream,
 167           available is # of compressed data, for playback it's
 168           remainder of buffer */
 169
 170        if (stream->runtime->total_bytes_available == 0 &&
 171                        stream->runtime->state == SNDRV_PCM_STATE_SETUP) {
 172                pr_debug("detected init and someone forgot to do a write\n");
 173                return stream->runtime->buffer_size;
 174        }
 175        pr_debug("app wrote %lld, DSP consumed %lld\n",
 176                        stream->runtime->total_bytes_available,
 177                        stream->runtime->total_bytes_transferred);
 178        if (stream->runtime->total_bytes_available ==
 179                                stream->runtime->total_bytes_transferred) {
 180                pr_debug("both pointers are same, returning full avail\n");
 181                return stream->runtime->buffer_size;
 182        }
 183
 184        /* FIXME: this routine isn't consistent, in one test we use
 185         * cumulative values and in the other byte offsets. Do we
 186         * really need the byte offsets if the cumulative values have
 187         * been updated? In the PCM interface app_ptr and hw_ptr are
 188         * already cumulative */
 189
 190        avail_calc = stream->runtime->buffer_size -
 191                (stream->runtime->app_pointer - stream->runtime->hw_pointer);
 192        pr_debug("calc avail as %ld, app_ptr %lld, hw+ptr %lld\n", avail_calc,
 193                        stream->runtime->app_pointer,
 194                        stream->runtime->hw_pointer);
 195        if (avail_calc >= stream->runtime->buffer_size)
 196                avail_calc -= stream->runtime->buffer_size;
 197        pr_debug("ret avail as %ld\n", avail_calc);
 198        avail->avail = avail_calc;
 199        return avail_calc;
 200}
 201
 202static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream)
 203{
 204        struct snd_compr_avail avail;
 205
 206        return snd_compr_calc_avail(stream, &avail);
 207}
 208
 209static int
 210snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
 211{
 212        struct snd_compr_avail ioctl_avail;
 213        size_t avail;
 214
 215        avail = snd_compr_calc_avail(stream, &ioctl_avail);
 216        ioctl_avail.avail = avail;
 217
 218        if (copy_to_user((__u64 __user *)arg,
 219                                &ioctl_avail, sizeof(ioctl_avail)))
 220                return -EFAULT;
 221        return 0;
 222}
 223
 224static int snd_compr_write_data(struct snd_compr_stream *stream,
 225               const char __user *buf, size_t count)
 226{
 227        void *dstn;
 228        size_t copy;
 229        struct snd_compr_runtime *runtime = stream->runtime;
 230
 231        dstn = runtime->buffer + runtime->app_pointer;
 232        pr_debug("copying %ld at %lld\n",
 233                        (unsigned long)count, runtime->app_pointer);
 234        if (count < runtime->buffer_size - runtime->app_pointer) {
 235                if (copy_from_user(dstn, buf, count))
 236                        return -EFAULT;
 237                runtime->app_pointer += count;
 238        } else {
 239                copy = runtime->buffer_size - runtime->app_pointer;
 240                if (copy_from_user(dstn, buf, copy))
 241                        return -EFAULT;
 242                if (copy_from_user(runtime->buffer, buf + copy, count - copy))
 243                        return -EFAULT;
 244                runtime->app_pointer = count - copy;
 245        }
 246        /* if DSP cares, let it know data has been written */
 247        if (stream->ops->ack)
 248                stream->ops->ack(stream, count);
 249        return count;
 250}
 251
 252static ssize_t snd_compr_write(struct file *f, const char __user *buf,
 253                size_t count, loff_t *offset)
 254{
 255        struct snd_compr_file *data = f->private_data;
 256        struct snd_compr_stream *stream;
 257        size_t avail;
 258        int retval;
 259
 260        if (snd_BUG_ON(!data))
 261                return -EFAULT;
 262
 263        stream = &data->stream;
 264        mutex_lock(&stream->device->lock);
 265        /* write is allowed when stream is running or has been steup */
 266        if (stream->runtime->state != SNDRV_PCM_STATE_SETUP &&
 267                        stream->runtime->state != SNDRV_PCM_STATE_RUNNING) {
 268                mutex_unlock(&stream->device->lock);
 269                return -EBADFD;
 270        }
 271
 272        avail = snd_compr_get_avail(stream);
 273        pr_debug("avail returned %ld\n", (unsigned long)avail);
 274        /* calculate how much we can write to buffer */
 275        if (avail > count)
 276                avail = count;
 277
 278        if (stream->ops->copy)
 279                retval = stream->ops->copy(stream, buf, avail);
 280        else
 281                retval = snd_compr_write_data(stream, buf, avail);
 282        if (retval > 0)
 283                stream->runtime->total_bytes_available += retval;
 284
 285        /* while initiating the stream, write should be called before START
 286         * call, so in setup move state */
 287        if (stream->runtime->state == SNDRV_PCM_STATE_SETUP) {
 288                stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
 289                pr_debug("stream prepared, Houston we are good to go\n");
 290        }
 291
 292        mutex_unlock(&stream->device->lock);
 293        return retval;
 294}
 295
 296
 297static ssize_t snd_compr_read(struct file *f, char __user *buf,
 298                size_t count, loff_t *offset)
 299{
 300        return -ENXIO;
 301}
 302
 303static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma)
 304{
 305        return -ENXIO;
 306}
 307
 308static inline int snd_compr_get_poll(struct snd_compr_stream *stream)
 309{
 310        if (stream->direction == SND_COMPRESS_PLAYBACK)
 311                return POLLOUT | POLLWRNORM;
 312        else
 313                return POLLIN | POLLRDNORM;
 314}
 315
 316static unsigned int snd_compr_poll(struct file *f, poll_table *wait)
 317{
 318        struct snd_compr_file *data = f->private_data;
 319        struct snd_compr_stream *stream;
 320        size_t avail;
 321        int retval = 0;
 322
 323        if (snd_BUG_ON(!data))
 324                return -EFAULT;
 325        stream = &data->stream;
 326        if (snd_BUG_ON(!stream))
 327                return -EFAULT;
 328
 329        mutex_lock(&stream->device->lock);
 330        if (stream->runtime->state == SNDRV_PCM_STATE_PAUSED ||
 331                        stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
 332                retval = -EBADFD;
 333                goto out;
 334        }
 335        poll_wait(f, &stream->runtime->sleep, wait);
 336
 337        avail = snd_compr_get_avail(stream);
 338        pr_debug("avail is %ld\n", (unsigned long)avail);
 339        /* check if we have at least one fragment to fill */
 340        switch (stream->runtime->state) {
 341        case SNDRV_PCM_STATE_DRAINING:
 342                /* stream has been woken up after drain is complete
 343                 * draining done so set stream state to stopped
 344                 */
 345                retval = snd_compr_get_poll(stream);
 346                stream->runtime->state = SNDRV_PCM_STATE_SETUP;
 347                break;
 348        case SNDRV_PCM_STATE_RUNNING:
 349        case SNDRV_PCM_STATE_PREPARED:
 350        case SNDRV_PCM_STATE_PAUSED:
 351                if (avail >= stream->runtime->fragment_size)
 352                        retval = snd_compr_get_poll(stream);
 353                break;
 354        default:
 355                if (stream->direction == SND_COMPRESS_PLAYBACK)
 356                        retval = POLLOUT | POLLWRNORM | POLLERR;
 357                else
 358                        retval = POLLIN | POLLRDNORM | POLLERR;
 359                break;
 360        }
 361out:
 362        mutex_unlock(&stream->device->lock);
 363        return retval;
 364}
 365
 366static int
 367snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg)
 368{
 369        int retval;
 370        struct snd_compr_caps caps;
 371
 372        if (!stream->ops->get_caps)
 373                return -ENXIO;
 374
 375        retval = stream->ops->get_caps(stream, &caps);
 376        if (retval)
 377                goto out;
 378        if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
 379                retval = -EFAULT;
 380out:
 381        return retval;
 382}
 383
 384static int
 385snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
 386{
 387        int retval;
 388        struct snd_compr_codec_caps *caps;
 389
 390        if (!stream->ops->get_codec_caps)
 391                return -ENXIO;
 392
 393        caps = kmalloc(sizeof(*caps), GFP_KERNEL);
 394        if (!caps)
 395                return -ENOMEM;
 396
 397        retval = stream->ops->get_codec_caps(stream, caps);
 398        if (retval)
 399                goto out;
 400        if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
 401                retval = -EFAULT;
 402
 403out:
 404        kfree(caps);
 405        return retval;
 406}
 407
 408/* revisit this with snd_pcm_preallocate_xxx */
 409static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
 410                struct snd_compr_params *params)
 411{
 412        unsigned int buffer_size;
 413        void *buffer;
 414
 415        buffer_size = params->buffer.fragment_size * params->buffer.fragments;
 416        if (stream->ops->copy) {
 417                buffer = NULL;
 418                /* if copy is defined the driver will be required to copy
 419                 * the data from core
 420                 */
 421        } else {
 422                buffer = kmalloc(buffer_size, GFP_KERNEL);
 423                if (!buffer)
 424                        return -ENOMEM;
 425        }
 426        stream->runtime->fragment_size = params->buffer.fragment_size;
 427        stream->runtime->fragments = params->buffer.fragments;
 428        stream->runtime->buffer = buffer;
 429        stream->runtime->buffer_size = buffer_size;
 430        return 0;
 431}
 432
 433static int snd_compress_check_input(struct snd_compr_params *params)
 434{
 435        /* first let's check the buffer parameter's */
 436        if (params->buffer.fragment_size == 0 ||
 437                        params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size)
 438                return -EINVAL;
 439
 440        /* now codec parameters */
 441        if (params->codec.id == 0 || params->codec.id > SND_AUDIOCODEC_MAX)
 442                return -EINVAL;
 443
 444        if (params->codec.ch_in == 0 || params->codec.ch_out == 0)
 445                return -EINVAL;
 446
 447        if (!(params->codec.sample_rate & SNDRV_PCM_RATE_8000_192000))
 448                return -EINVAL;
 449
 450        return 0;
 451}
 452
 453static int
 454snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
 455{
 456        struct snd_compr_params *params;
 457        int retval;
 458
 459        if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
 460                /*
 461                 * we should allow parameter change only when stream has been
 462                 * opened not in other cases
 463                 */
 464                params = kmalloc(sizeof(*params), GFP_KERNEL);
 465                if (!params)
 466                        return -ENOMEM;
 467                if (copy_from_user(params, (void __user *)arg, sizeof(*params))) {
 468                        retval = -EFAULT;
 469                        goto out;
 470                }
 471
 472                retval = snd_compress_check_input(params);
 473                if (retval)
 474                        goto out;
 475
 476                retval = snd_compr_allocate_buffer(stream, params);
 477                if (retval) {
 478                        retval = -ENOMEM;
 479                        goto out;
 480                }
 481
 482                retval = stream->ops->set_params(stream, params);
 483                if (retval)
 484                        goto out;
 485                stream->runtime->state = SNDRV_PCM_STATE_SETUP;
 486        } else {
 487                return -EPERM;
 488        }
 489out:
 490        kfree(params);
 491        return retval;
 492}
 493
 494static int
 495snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
 496{
 497        struct snd_codec *params;
 498        int retval;
 499
 500        if (!stream->ops->get_params)
 501                return -EBADFD;
 502
 503        params = kmalloc(sizeof(*params), GFP_KERNEL);
 504        if (!params)
 505                return -ENOMEM;
 506        retval = stream->ops->get_params(stream, params);
 507        if (retval)
 508                goto out;
 509        if (copy_to_user((char __user *)arg, params, sizeof(*params)))
 510                retval = -EFAULT;
 511
 512out:
 513        kfree(params);
 514        return retval;
 515}
 516
 517static inline int
 518snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
 519{
 520        struct snd_compr_tstamp tstamp;
 521
 522        snd_compr_update_tstamp(stream, &tstamp);
 523        return copy_to_user((struct snd_compr_tstamp __user *)arg,
 524                &tstamp, sizeof(tstamp)) ? -EFAULT : 0;
 525}
 526
 527static int snd_compr_pause(struct snd_compr_stream *stream)
 528{
 529        int retval;
 530
 531        if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
 532                return -EPERM;
 533        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
 534        if (!retval)
 535                stream->runtime->state = SNDRV_PCM_STATE_PAUSED;
 536        return retval;
 537}
 538
 539static int snd_compr_resume(struct snd_compr_stream *stream)
 540{
 541        int retval;
 542
 543        if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED)
 544                return -EPERM;
 545        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
 546        if (!retval)
 547                stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
 548        return retval;
 549}
 550
 551static int snd_compr_start(struct snd_compr_stream *stream)
 552{
 553        int retval;
 554
 555        if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
 556                return -EPERM;
 557        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);
 558        if (!retval)
 559                stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
 560        return retval;
 561}
 562
 563static int snd_compr_stop(struct snd_compr_stream *stream)
 564{
 565        int retval;
 566
 567        if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
 568                        stream->runtime->state == SNDRV_PCM_STATE_SETUP)
 569                return -EPERM;
 570        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
 571        if (!retval) {
 572                stream->runtime->state = SNDRV_PCM_STATE_SETUP;
 573                wake_up(&stream->runtime->sleep);
 574                stream->runtime->hw_pointer = 0;
 575                stream->runtime->app_pointer = 0;
 576                stream->runtime->total_bytes_available = 0;
 577                stream->runtime->total_bytes_transferred = 0;
 578        }
 579        return retval;
 580}
 581
 582static int snd_compr_drain(struct snd_compr_stream *stream)
 583{
 584        int retval;
 585
 586        if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
 587                        stream->runtime->state == SNDRV_PCM_STATE_SETUP)
 588                return -EPERM;
 589        retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
 590        if (!retval) {
 591                stream->runtime->state = SNDRV_PCM_STATE_DRAINING;
 592                wake_up(&stream->runtime->sleep);
 593        }
 594        return retval;
 595}
 596
 597static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
 598{
 599        struct snd_compr_file *data = f->private_data;
 600        struct snd_compr_stream *stream;
 601        int retval = -ENOTTY;
 602
 603        if (snd_BUG_ON(!data))
 604                return -EFAULT;
 605        stream = &data->stream;
 606        if (snd_BUG_ON(!stream))
 607                return -EFAULT;
 608        mutex_lock(&stream->device->lock);
 609        switch (_IOC_NR(cmd)) {
 610        case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
 611                put_user(SNDRV_COMPRESS_VERSION,
 612                                (int __user *)arg) ? -EFAULT : 0;
 613                break;
 614        case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
 615                retval = snd_compr_get_caps(stream, arg);
 616                break;
 617        case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
 618                retval = snd_compr_get_codec_caps(stream, arg);
 619                break;
 620        case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
 621                retval = snd_compr_set_params(stream, arg);
 622                break;
 623        case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
 624                retval = snd_compr_get_params(stream, arg);
 625                break;
 626        case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
 627                retval = snd_compr_tstamp(stream, arg);
 628                break;
 629        case _IOC_NR(SNDRV_COMPRESS_AVAIL):
 630                retval = snd_compr_ioctl_avail(stream, arg);
 631                break;
 632        case _IOC_NR(SNDRV_COMPRESS_PAUSE):
 633                retval = snd_compr_pause(stream);
 634                break;
 635        case _IOC_NR(SNDRV_COMPRESS_RESUME):
 636                retval = snd_compr_resume(stream);
 637                break;
 638        case _IOC_NR(SNDRV_COMPRESS_START):
 639                retval = snd_compr_start(stream);
 640                break;
 641        case _IOC_NR(SNDRV_COMPRESS_STOP):
 642                retval = snd_compr_stop(stream);
 643                break;
 644        case _IOC_NR(SNDRV_COMPRESS_DRAIN):
 645                retval = snd_compr_drain(stream);
 646                break;
 647        }
 648        mutex_unlock(&stream->device->lock);
 649        return retval;
 650}
 651
 652static const struct file_operations snd_compr_file_ops = {
 653                .owner =        THIS_MODULE,
 654                .open =         snd_compr_open,
 655                .release =      snd_compr_free,
 656                .write =        snd_compr_write,
 657                .read =         snd_compr_read,
 658                .unlocked_ioctl = snd_compr_ioctl,
 659                .mmap =         snd_compr_mmap,
 660                .poll =         snd_compr_poll,
 661};
 662
 663static int snd_compress_dev_register(struct snd_device *device)
 664{
 665        int ret = -EINVAL;
 666        char str[16];
 667        struct snd_compr *compr;
 668
 669        if (snd_BUG_ON(!device || !device->device_data))
 670                return -EBADFD;
 671        compr = device->device_data;
 672
 673        sprintf(str, "comprC%iD%i", compr->card->number, compr->device);
 674        pr_debug("reg %s for device %s, direction %d\n", str, compr->name,
 675                        compr->direction);
 676        /* register compressed device */
 677        ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
 678                        compr->device, &snd_compr_file_ops, compr, str);
 679        if (ret < 0) {
 680                pr_err("snd_register_device failed\n %d", ret);
 681                return ret;
 682        }
 683        return ret;
 684
 685}
 686
 687static int snd_compress_dev_disconnect(struct snd_device *device)
 688{
 689        struct snd_compr *compr;
 690
 691        compr = device->device_data;
 692        snd_unregister_device(compr->direction, compr->card, compr->device);
 693        return 0;
 694}
 695
 696/*
 697 * snd_compress_new: create new compress device
 698 * @card: sound card pointer
 699 * @device: device number
 700 * @dirn: device direction, should be of type enum snd_compr_direction
 701 * @compr: compress device pointer
 702 */
 703int snd_compress_new(struct snd_card *card, int device,
 704                        int dirn, struct snd_compr *compr)
 705{
 706        static struct snd_device_ops ops = {
 707                .dev_free = NULL,
 708                .dev_register = snd_compress_dev_register,
 709                .dev_disconnect = snd_compress_dev_disconnect,
 710        };
 711
 712        compr->card = card;
 713        compr->device = device;
 714        compr->direction = dirn;
 715        return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
 716}
 717EXPORT_SYMBOL_GPL(snd_compress_new);
 718
 719static int snd_compress_add_device(struct snd_compr *device)
 720{
 721        int ret;
 722
 723        if (!device->card)
 724                return -EINVAL;
 725
 726        /* register the card */
 727        ret = snd_card_register(device->card);
 728        if (ret)
 729                goto out;
 730        return 0;
 731
 732out:
 733        pr_err("failed with %d\n", ret);
 734        return ret;
 735
 736}
 737
 738static int snd_compress_remove_device(struct snd_compr *device)
 739{
 740        return snd_card_free(device->card);
 741}
 742
 743/**
 744 * snd_compress_register - register compressed device
 745 *
 746 * @device: compressed device to register
 747 */
 748int snd_compress_register(struct snd_compr *device)
 749{
 750        int retval;
 751
 752        if (device->name == NULL || device->dev == NULL || device->ops == NULL)
 753                return -EINVAL;
 754
 755        pr_debug("Registering compressed device %s\n", device->name);
 756        if (snd_BUG_ON(!device->ops->open))
 757                return -EINVAL;
 758        if (snd_BUG_ON(!device->ops->free))
 759                return -EINVAL;
 760        if (snd_BUG_ON(!device->ops->set_params))
 761                return -EINVAL;
 762        if (snd_BUG_ON(!device->ops->trigger))
 763                return -EINVAL;
 764
 765        mutex_init(&device->lock);
 766
 767        /* register a compressed card */
 768        mutex_lock(&device_mutex);
 769        retval = snd_compress_add_device(device);
 770        mutex_unlock(&device_mutex);
 771        return retval;
 772}
 773EXPORT_SYMBOL_GPL(snd_compress_register);
 774
 775int snd_compress_deregister(struct snd_compr *device)
 776{
 777        pr_debug("Removing compressed device %s\n", device->name);
 778        mutex_lock(&device_mutex);
 779        snd_compress_remove_device(device);
 780        mutex_unlock(&device_mutex);
 781        return 0;
 782}
 783EXPORT_SYMBOL_GPL(snd_compress_deregister);
 784
 785static int __init snd_compress_init(void)
 786{
 787        return 0;
 788}
 789
 790static void __exit snd_compress_exit(void)
 791{
 792}
 793
 794module_init(snd_compress_init);
 795module_exit(snd_compress_exit);
 796
 797MODULE_DESCRIPTION("ALSA Compressed offload framework");
 798MODULE_AUTHOR("Vinod Koul <vinod.koul@linux.intel.com>");
 799MODULE_LICENSE("GPL v2");
 800
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.