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