.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * compress_core.c - compress offload core |
---|
3 | 4 | * |
---|
.. | .. |
---|
6 | 7 | * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> |
---|
7 | 8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
---|
8 | 9 | * |
---|
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 | 10 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
---|
23 | | - * |
---|
24 | 11 | */ |
---|
25 | 12 | #define FORMAT(fmt) "%s: %d: " fmt, __func__, __LINE__ |
---|
26 | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt) |
---|
.. | .. |
---|
45 | 32 | #include <sound/compress_params.h> |
---|
46 | 33 | #include <sound/compress_offload.h> |
---|
47 | 34 | #include <sound/compress_driver.h> |
---|
| 35 | + |
---|
| 36 | +#ifndef __GENKSYMS__ |
---|
| 37 | +#include <trace/hooks/snd_compr.h> |
---|
| 38 | +#endif |
---|
48 | 39 | |
---|
49 | 40 | /* struct snd_compr_codec_caps overflows the ioctl bit size for some |
---|
50 | 41 | * architectures, so we need to disable the relevant ioctls. |
---|
.. | .. |
---|
171 | 162 | } |
---|
172 | 163 | |
---|
173 | 164 | data->stream.ops->free(&data->stream); |
---|
174 | | - kfree(data->stream.runtime->buffer); |
---|
| 165 | + if (!data->stream.runtime->dma_buffer_p) |
---|
| 166 | + kfree(data->stream.runtime->buffer); |
---|
175 | 167 | kfree(data->stream.runtime); |
---|
176 | 168 | kfree(data); |
---|
177 | 169 | return 0; |
---|
.. | .. |
---|
183 | 175 | if (!stream->ops->pointer) |
---|
184 | 176 | return -ENOTSUPP; |
---|
185 | 177 | stream->ops->pointer(stream, tstamp); |
---|
186 | | - pr_debug("dsp consumed till %d total %llu bytes\n", |
---|
| 178 | + pr_debug("dsp consumed till %d total %d bytes\n", |
---|
187 | 179 | tstamp->byte_offset, tstamp->copied_total); |
---|
188 | 180 | if (stream->direction == SND_COMPRESS_PLAYBACK) |
---|
189 | 181 | stream->runtime->total_bytes_transferred = tstamp->copied_total; |
---|
.. | .. |
---|
500 | 492 | } |
---|
501 | 493 | #endif /* !COMPR_CODEC_CAPS_OVERFLOW */ |
---|
502 | 494 | |
---|
| 495 | +int snd_compr_malloc_pages(struct snd_compr_stream *stream, size_t size) |
---|
| 496 | +{ |
---|
| 497 | + struct snd_dma_buffer *dmab; |
---|
| 498 | + int ret; |
---|
| 499 | + |
---|
| 500 | + if (snd_BUG_ON(!(stream) || !(stream)->runtime)) |
---|
| 501 | + return -EINVAL; |
---|
| 502 | + dmab = kzalloc(sizeof(*dmab), GFP_KERNEL); |
---|
| 503 | + if (!dmab) |
---|
| 504 | + return -ENOMEM; |
---|
| 505 | + dmab->dev = stream->dma_buffer.dev; |
---|
| 506 | + ret = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev, size, dmab); |
---|
| 507 | + if (ret < 0) { |
---|
| 508 | + kfree(dmab); |
---|
| 509 | + return ret; |
---|
| 510 | + } |
---|
| 511 | + |
---|
| 512 | + snd_compr_set_runtime_buffer(stream, dmab); |
---|
| 513 | + stream->runtime->dma_bytes = size; |
---|
| 514 | + return 1; |
---|
| 515 | +} |
---|
| 516 | +EXPORT_SYMBOL(snd_compr_malloc_pages); |
---|
| 517 | + |
---|
| 518 | +int snd_compr_free_pages(struct snd_compr_stream *stream) |
---|
| 519 | +{ |
---|
| 520 | + struct snd_compr_runtime *runtime; |
---|
| 521 | + |
---|
| 522 | + if (snd_BUG_ON(!(stream) || !(stream)->runtime)) |
---|
| 523 | + return -EINVAL; |
---|
| 524 | + runtime = stream->runtime; |
---|
| 525 | + if (runtime->dma_area == NULL) |
---|
| 526 | + return 0; |
---|
| 527 | + if (runtime->dma_buffer_p != &stream->dma_buffer) { |
---|
| 528 | + /* It's a newly allocated buffer. Release it now. */ |
---|
| 529 | + snd_dma_free_pages(runtime->dma_buffer_p); |
---|
| 530 | + kfree(runtime->dma_buffer_p); |
---|
| 531 | + } |
---|
| 532 | + |
---|
| 533 | + snd_compr_set_runtime_buffer(stream, NULL); |
---|
| 534 | + return 0; |
---|
| 535 | +} |
---|
| 536 | +EXPORT_SYMBOL(snd_compr_free_pages); |
---|
| 537 | + |
---|
503 | 538 | /* revisit this with snd_pcm_preallocate_xxx */ |
---|
504 | 539 | static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, |
---|
505 | 540 | struct snd_compr_params *params) |
---|
506 | 541 | { |
---|
507 | 542 | unsigned int buffer_size; |
---|
508 | | - void *buffer; |
---|
| 543 | + void *buffer = NULL; |
---|
509 | 544 | |
---|
510 | 545 | buffer_size = params->buffer.fragment_size * params->buffer.fragments; |
---|
511 | 546 | if (stream->ops->copy) { |
---|
.. | .. |
---|
514 | 549 | * the data from core |
---|
515 | 550 | */ |
---|
516 | 551 | } else { |
---|
517 | | - buffer = kmalloc(buffer_size, GFP_KERNEL); |
---|
| 552 | + if (stream->runtime->dma_buffer_p) { |
---|
| 553 | + |
---|
| 554 | + if (buffer_size > stream->runtime->dma_buffer_p->bytes) |
---|
| 555 | + dev_err(&stream->device->dev, |
---|
| 556 | + "Not enough DMA buffer"); |
---|
| 557 | + else |
---|
| 558 | + buffer = stream->runtime->dma_buffer_p->area; |
---|
| 559 | + |
---|
| 560 | + } else { |
---|
| 561 | + buffer = kmalloc(buffer_size, GFP_KERNEL); |
---|
| 562 | + } |
---|
| 563 | + |
---|
518 | 564 | if (!buffer) |
---|
519 | 565 | return -ENOMEM; |
---|
520 | 566 | } |
---|
.. | .. |
---|
666 | 712 | static int snd_compr_pause(struct snd_compr_stream *stream) |
---|
667 | 713 | { |
---|
668 | 714 | int retval; |
---|
| 715 | + bool use_pause_in_drain = false; |
---|
| 716 | + bool leave_draining_state = false; |
---|
| 717 | + |
---|
| 718 | + trace_android_vh_snd_compr_use_pause_in_drain(&use_pause_in_drain, |
---|
| 719 | + &leave_draining_state); |
---|
| 720 | + |
---|
| 721 | + if (use_pause_in_drain && stream->runtime->state == SNDRV_PCM_STATE_DRAINING) { |
---|
| 722 | + retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH); |
---|
| 723 | + if (!retval && leave_draining_state) { |
---|
| 724 | + stream->runtime->state = SNDRV_PCM_STATE_PAUSED; |
---|
| 725 | + wake_up(&stream->runtime->sleep); |
---|
| 726 | + } |
---|
| 727 | + return retval; |
---|
| 728 | + } |
---|
669 | 729 | |
---|
670 | 730 | if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING) |
---|
671 | 731 | return -EPERM; |
---|
.. | .. |
---|
678 | 738 | static int snd_compr_resume(struct snd_compr_stream *stream) |
---|
679 | 739 | { |
---|
680 | 740 | int retval; |
---|
| 741 | + bool use_pause_in_drain = false; |
---|
| 742 | + bool leave_draining_state = false; |
---|
| 743 | + |
---|
| 744 | + trace_android_vh_snd_compr_use_pause_in_drain(&use_pause_in_drain, |
---|
| 745 | + &leave_draining_state); |
---|
| 746 | + |
---|
| 747 | + if (use_pause_in_drain && stream->runtime->state == SNDRV_PCM_STATE_DRAINING) |
---|
| 748 | + return stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE); |
---|
681 | 749 | |
---|
682 | 750 | if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED) |
---|
683 | 751 | return -EPERM; |
---|
.. | .. |
---|
723 | 791 | |
---|
724 | 792 | retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP); |
---|
725 | 793 | if (!retval) { |
---|
726 | | - stream->runtime->state = SNDRV_PCM_STATE_SETUP; |
---|
727 | | - wake_up(&stream->runtime->sleep); |
---|
| 794 | + /* clear flags and stop any drain wait */ |
---|
| 795 | + stream->partial_drain = false; |
---|
| 796 | + stream->metadata_set = false; |
---|
| 797 | + snd_compr_drain_notify(stream); |
---|
728 | 798 | stream->runtime->total_bytes_available = 0; |
---|
729 | 799 | stream->runtime->total_bytes_transferred = 0; |
---|
730 | 800 | } |
---|
.. | .. |
---|
770 | 840 | } |
---|
771 | 841 | EXPORT_SYMBOL_GPL(snd_compr_stop_error); |
---|
772 | 842 | |
---|
| 843 | +static int snd_compress_wait_for_drain(struct snd_compr_stream *stream) |
---|
| 844 | +{ |
---|
| 845 | + int ret; |
---|
| 846 | + |
---|
| 847 | + /* |
---|
| 848 | + * We are called with lock held. So drop the lock while we wait for |
---|
| 849 | + * drain complete notification from the driver |
---|
| 850 | + * |
---|
| 851 | + * It is expected that driver will notify the drain completion and then |
---|
| 852 | + * stream will be moved to SETUP state, even if draining resulted in an |
---|
| 853 | + * error. We can trigger next track after this. |
---|
| 854 | + */ |
---|
| 855 | + stream->runtime->state = SNDRV_PCM_STATE_DRAINING; |
---|
| 856 | + mutex_unlock(&stream->device->lock); |
---|
| 857 | + |
---|
| 858 | + /* we wait for drain to complete here, drain can return when |
---|
| 859 | + * interruption occurred, wait returned error or success. |
---|
| 860 | + * For the first two cases we don't do anything different here and |
---|
| 861 | + * return after waking up |
---|
| 862 | + */ |
---|
| 863 | + |
---|
| 864 | + ret = wait_event_interruptible(stream->runtime->sleep, |
---|
| 865 | + (stream->runtime->state != SNDRV_PCM_STATE_DRAINING)); |
---|
| 866 | + if (ret == -ERESTARTSYS) |
---|
| 867 | + pr_debug("wait aborted by a signal\n"); |
---|
| 868 | + else if (ret) |
---|
| 869 | + pr_debug("wait for drain failed with %d\n", ret); |
---|
| 870 | + |
---|
| 871 | + |
---|
| 872 | + wake_up(&stream->runtime->sleep); |
---|
| 873 | + mutex_lock(&stream->device->lock); |
---|
| 874 | + |
---|
| 875 | + return ret; |
---|
| 876 | +} |
---|
| 877 | + |
---|
773 | 878 | static int snd_compr_drain(struct snd_compr_stream *stream) |
---|
774 | 879 | { |
---|
775 | 880 | int retval; |
---|
.. | .. |
---|
787 | 892 | } |
---|
788 | 893 | |
---|
789 | 894 | retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN); |
---|
790 | | - if (!retval) { |
---|
791 | | - stream->runtime->state = SNDRV_PCM_STATE_DRAINING; |
---|
| 895 | + if (retval) { |
---|
| 896 | + pr_debug("SND_COMPR_TRIGGER_DRAIN failed %d\n", retval); |
---|
792 | 897 | wake_up(&stream->runtime->sleep); |
---|
793 | 898 | return retval; |
---|
794 | 899 | } |
---|
795 | 900 | |
---|
796 | | - return retval; |
---|
| 901 | + return snd_compress_wait_for_drain(stream); |
---|
797 | 902 | } |
---|
798 | 903 | |
---|
799 | 904 | static int snd_compr_next_track(struct snd_compr_stream *stream) |
---|
.. | .. |
---|
846 | 951 | if (stream->next_track == false) |
---|
847 | 952 | return -EPERM; |
---|
848 | 953 | |
---|
| 954 | + stream->partial_drain = true; |
---|
849 | 955 | retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN); |
---|
850 | | - |
---|
851 | | - stream->next_track = false; |
---|
852 | | - return retval; |
---|
853 | | -} |
---|
854 | | - |
---|
855 | | -static int snd_compr_set_next_track_param(struct snd_compr_stream *stream, |
---|
856 | | - unsigned long arg) |
---|
857 | | -{ |
---|
858 | | - union snd_codec_options codec_options; |
---|
859 | | - int retval; |
---|
860 | | - |
---|
861 | | - /* set next track params when stream is running or has been setup */ |
---|
862 | | - if (stream->runtime->state != SNDRV_PCM_STATE_SETUP && |
---|
863 | | - stream->runtime->state != SNDRV_PCM_STATE_RUNNING) |
---|
864 | | - return -EPERM; |
---|
865 | | - |
---|
866 | | - if (copy_from_user(&codec_options, (void __user *)arg, |
---|
867 | | - sizeof(codec_options))) |
---|
868 | | - return -EFAULT; |
---|
869 | | - |
---|
870 | | - retval = stream->ops->set_next_track_param(stream, &codec_options); |
---|
871 | | - return retval; |
---|
872 | | -} |
---|
873 | | - |
---|
874 | | -static int snd_compress_simple_ioctls(struct file *file, |
---|
875 | | - struct snd_compr_stream *stream, |
---|
876 | | - unsigned int cmd, unsigned long arg) |
---|
877 | | -{ |
---|
878 | | - int retval = -ENOTTY; |
---|
879 | | - |
---|
880 | | - switch (_IOC_NR(cmd)) { |
---|
881 | | - case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION): |
---|
882 | | - retval = put_user(SNDRV_COMPRESS_VERSION, |
---|
883 | | - (int __user *)arg) ? -EFAULT : 0; |
---|
884 | | - break; |
---|
885 | | - |
---|
886 | | - case _IOC_NR(SNDRV_COMPRESS_GET_CAPS): |
---|
887 | | - retval = snd_compr_get_caps(stream, arg); |
---|
888 | | - break; |
---|
889 | | - |
---|
890 | | -#ifndef COMPR_CODEC_CAPS_OVERFLOW |
---|
891 | | - case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS): |
---|
892 | | - retval = snd_compr_get_codec_caps(stream, arg); |
---|
893 | | - break; |
---|
894 | | -#endif |
---|
895 | | - |
---|
896 | | - case _IOC_NR(SNDRV_COMPRESS_TSTAMP): |
---|
897 | | - retval = snd_compr_tstamp(stream, arg); |
---|
898 | | - break; |
---|
899 | | - |
---|
900 | | - case _IOC_NR(SNDRV_COMPRESS_AVAIL): |
---|
901 | | - retval = snd_compr_ioctl_avail(stream, arg); |
---|
902 | | - break; |
---|
903 | | - |
---|
904 | | - case _IOC_NR(SNDRV_COMPRESS_DRAIN): |
---|
905 | | - retval = snd_compr_drain(stream); |
---|
906 | | - break; |
---|
907 | | - |
---|
908 | | - case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN): |
---|
909 | | - retval = snd_compr_partial_drain(stream); |
---|
910 | | - break; |
---|
| 956 | + if (retval) { |
---|
| 957 | + pr_debug("Partial drain returned failure\n"); |
---|
| 958 | + wake_up(&stream->runtime->sleep); |
---|
| 959 | + return retval; |
---|
911 | 960 | } |
---|
912 | 961 | |
---|
913 | | - return retval; |
---|
| 962 | + stream->next_track = false; |
---|
| 963 | + return snd_compress_wait_for_drain(stream); |
---|
914 | 964 | } |
---|
915 | 965 | |
---|
916 | 966 | static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) |
---|
.. | .. |
---|
926 | 976 | |
---|
927 | 977 | mutex_lock(&stream->device->lock); |
---|
928 | 978 | switch (_IOC_NR(cmd)) { |
---|
| 979 | + case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION): |
---|
| 980 | + retval = put_user(SNDRV_COMPRESS_VERSION, |
---|
| 981 | + (int __user *)arg) ? -EFAULT : 0; |
---|
| 982 | + break; |
---|
| 983 | + case _IOC_NR(SNDRV_COMPRESS_GET_CAPS): |
---|
| 984 | + retval = snd_compr_get_caps(stream, arg); |
---|
| 985 | + break; |
---|
| 986 | +#ifndef COMPR_CODEC_CAPS_OVERFLOW |
---|
| 987 | + case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS): |
---|
| 988 | + retval = snd_compr_get_codec_caps(stream, arg); |
---|
| 989 | + break; |
---|
| 990 | +#endif |
---|
929 | 991 | case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS): |
---|
930 | 992 | retval = snd_compr_set_params(stream, arg); |
---|
931 | 993 | break; |
---|
932 | | - |
---|
933 | 994 | case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS): |
---|
934 | 995 | retval = snd_compr_get_params(stream, arg); |
---|
935 | 996 | break; |
---|
936 | | - |
---|
937 | 997 | case _IOC_NR(SNDRV_COMPRESS_SET_METADATA): |
---|
938 | 998 | retval = snd_compr_set_metadata(stream, arg); |
---|
939 | 999 | break; |
---|
940 | | - |
---|
941 | 1000 | case _IOC_NR(SNDRV_COMPRESS_GET_METADATA): |
---|
942 | 1001 | retval = snd_compr_get_metadata(stream, arg); |
---|
943 | 1002 | break; |
---|
944 | | - |
---|
| 1003 | + case _IOC_NR(SNDRV_COMPRESS_TSTAMP): |
---|
| 1004 | + retval = snd_compr_tstamp(stream, arg); |
---|
| 1005 | + break; |
---|
| 1006 | + case _IOC_NR(SNDRV_COMPRESS_AVAIL): |
---|
| 1007 | + retval = snd_compr_ioctl_avail(stream, arg); |
---|
| 1008 | + break; |
---|
945 | 1009 | case _IOC_NR(SNDRV_COMPRESS_PAUSE): |
---|
946 | 1010 | retval = snd_compr_pause(stream); |
---|
947 | 1011 | break; |
---|
948 | | - |
---|
949 | 1012 | case _IOC_NR(SNDRV_COMPRESS_RESUME): |
---|
950 | 1013 | retval = snd_compr_resume(stream); |
---|
951 | 1014 | break; |
---|
952 | | - |
---|
953 | 1015 | case _IOC_NR(SNDRV_COMPRESS_START): |
---|
954 | 1016 | retval = snd_compr_start(stream); |
---|
955 | 1017 | break; |
---|
956 | | - |
---|
957 | 1018 | case _IOC_NR(SNDRV_COMPRESS_STOP): |
---|
958 | 1019 | retval = snd_compr_stop(stream); |
---|
959 | 1020 | break; |
---|
960 | | - |
---|
| 1021 | + case _IOC_NR(SNDRV_COMPRESS_DRAIN): |
---|
| 1022 | + retval = snd_compr_drain(stream); |
---|
| 1023 | + break; |
---|
| 1024 | + case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN): |
---|
| 1025 | + retval = snd_compr_partial_drain(stream); |
---|
| 1026 | + break; |
---|
961 | 1027 | case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK): |
---|
962 | 1028 | retval = snd_compr_next_track(stream); |
---|
963 | 1029 | break; |
---|
964 | | - |
---|
965 | | - case _IOC_NR(SNDRV_COMPRESS_SET_NEXT_TRACK_PARAM): |
---|
966 | | - retval = snd_compr_set_next_track_param(stream, arg); |
---|
967 | | - break; |
---|
968 | | - |
---|
969 | | - default: |
---|
970 | | - mutex_unlock(&stream->device->lock); |
---|
971 | | - return snd_compress_simple_ioctls(f, stream, cmd, arg); |
---|
972 | 1030 | |
---|
973 | 1031 | } |
---|
974 | 1032 | mutex_unlock(&stream->device->lock); |
---|
.. | .. |
---|
1000 | 1058 | |
---|
1001 | 1059 | static int snd_compress_dev_register(struct snd_device *device) |
---|
1002 | 1060 | { |
---|
1003 | | - int ret = -EINVAL; |
---|
| 1061 | + int ret; |
---|
1004 | 1062 | struct snd_compr *compr; |
---|
1005 | 1063 | |
---|
1006 | 1064 | if (snd_BUG_ON(!device || !device->device_data)) |
---|
.. | .. |
---|
1055 | 1113 | if (!entry) |
---|
1056 | 1114 | return -ENOMEM; |
---|
1057 | 1115 | entry->mode = S_IFDIR | 0555; |
---|
1058 | | - if (snd_info_register(entry) < 0) { |
---|
1059 | | - snd_info_free_entry(entry); |
---|
1060 | | - return -ENOMEM; |
---|
1061 | | - } |
---|
1062 | 1116 | compr->proc_root = entry; |
---|
1063 | 1117 | |
---|
1064 | 1118 | entry = snd_info_create_card_entry(compr->card, "info", |
---|
1065 | 1119 | compr->proc_root); |
---|
1066 | | - if (entry) { |
---|
| 1120 | + if (entry) |
---|
1067 | 1121 | snd_info_set_text_ops(entry, compr, |
---|
1068 | 1122 | snd_compress_proc_info_read); |
---|
1069 | | - if (snd_info_register(entry) < 0) { |
---|
1070 | | - snd_info_free_entry(entry); |
---|
1071 | | - entry = NULL; |
---|
1072 | | - } |
---|
1073 | | - } |
---|
1074 | 1123 | compr->proc_info_entry = entry; |
---|
1075 | 1124 | |
---|
1076 | 1125 | return 0; |
---|
.. | .. |
---|
1123 | 1172 | int snd_compress_new(struct snd_card *card, int device, |
---|
1124 | 1173 | int dirn, const char *id, struct snd_compr *compr) |
---|
1125 | 1174 | { |
---|
1126 | | - static struct snd_device_ops ops = { |
---|
| 1175 | + static const struct snd_device_ops ops = { |
---|
1127 | 1176 | .dev_free = snd_compress_dev_free, |
---|
1128 | 1177 | .dev_register = snd_compress_dev_register, |
---|
1129 | 1178 | .dev_disconnect = snd_compress_dev_disconnect, |
---|