| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Digital Audio (PCM) abstract layer / OSS compatible |
|---|
| 3 | 4 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
|---|
| 4 | | - * |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 8 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 9 | | - * (at your option) any later version. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License |
|---|
| 17 | | - * along with this program; if not, write to the Free Software |
|---|
| 18 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 19 | | - * |
|---|
| 20 | 5 | */ |
|---|
| 21 | 6 | |
|---|
| 22 | 7 | #if 0 |
|---|
| .. | .. |
|---|
| 789 | 774 | |
|---|
| 790 | 775 | if (oss_period_size < 16) |
|---|
| 791 | 776 | return -EINVAL; |
|---|
| 777 | + |
|---|
| 778 | + /* don't allocate too large period; 1MB period must be enough */ |
|---|
| 779 | + if (oss_period_size > 1024 * 1024) |
|---|
| 780 | + return -ENOMEM; |
|---|
| 781 | + |
|---|
| 792 | 782 | runtime->oss.period_bytes = oss_period_size; |
|---|
| 793 | 783 | runtime->oss.period_frames = 1; |
|---|
| 794 | 784 | runtime->oss.periods = oss_periods; |
|---|
| .. | .. |
|---|
| 918 | 908 | sformat = snd_pcm_plug_slave_format(format, sformat_mask); |
|---|
| 919 | 909 | |
|---|
| 920 | 910 | if ((__force int)sformat < 0 || |
|---|
| 921 | | - !snd_mask_test(sformat_mask, (__force int)sformat)) { |
|---|
| 922 | | - for (sformat = (__force snd_pcm_format_t)0; |
|---|
| 923 | | - (__force int)sformat <= (__force int)SNDRV_PCM_FORMAT_LAST; |
|---|
| 924 | | - sformat = (__force snd_pcm_format_t)((__force int)sformat + 1)) { |
|---|
| 925 | | - if (snd_mask_test(sformat_mask, (__force int)sformat) && |
|---|
| 911 | + !snd_mask_test_format(sformat_mask, sformat)) { |
|---|
| 912 | + pcm_for_each_format(sformat) { |
|---|
| 913 | + if (snd_mask_test_format(sformat_mask, sformat) && |
|---|
| 926 | 914 | snd_pcm_oss_format_to(sformat) >= 0) |
|---|
| 927 | | - break; |
|---|
| 915 | + goto format_found; |
|---|
| 928 | 916 | } |
|---|
| 929 | | - if ((__force int)sformat > (__force int)SNDRV_PCM_FORMAT_LAST) { |
|---|
| 930 | | - pcm_dbg(substream->pcm, "Cannot find a format!!!\n"); |
|---|
| 931 | | - err = -EINVAL; |
|---|
| 932 | | - goto failure; |
|---|
| 933 | | - } |
|---|
| 917 | + pcm_dbg(substream->pcm, "Cannot find a format!!!\n"); |
|---|
| 918 | + err = -EINVAL; |
|---|
| 919 | + goto failure; |
|---|
| 934 | 920 | } |
|---|
| 921 | + format_found: |
|---|
| 935 | 922 | err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, (__force int)sformat, 0); |
|---|
| 936 | 923 | if (err < 0) |
|---|
| 937 | 924 | goto failure; |
|---|
| .. | .. |
|---|
| 1060 | 1047 | goto failure; |
|---|
| 1061 | 1048 | } |
|---|
| 1062 | 1049 | #endif |
|---|
| 1063 | | - oss_period_size *= oss_frame_size; |
|---|
| 1064 | | - |
|---|
| 1065 | | - oss_buffer_size = oss_period_size * runtime->oss.periods; |
|---|
| 1066 | | - if (oss_buffer_size < 0) { |
|---|
| 1050 | + oss_period_size = array_size(oss_period_size, oss_frame_size); |
|---|
| 1051 | + oss_buffer_size = array_size(oss_period_size, runtime->oss.periods); |
|---|
| 1052 | + if (oss_buffer_size <= 0) { |
|---|
| 1067 | 1053 | err = -EINVAL; |
|---|
| 1068 | 1054 | goto failure; |
|---|
| 1069 | 1055 | } |
|---|
| .. | .. |
|---|
| 1254 | 1240 | if (ret < 0) |
|---|
| 1255 | 1241 | break; |
|---|
| 1256 | 1242 | } |
|---|
| 1243 | + mutex_unlock(&runtime->oss.params_lock); |
|---|
| 1257 | 1244 | ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true, |
|---|
| 1258 | 1245 | frames, in_kernel); |
|---|
| 1246 | + mutex_lock(&runtime->oss.params_lock); |
|---|
| 1259 | 1247 | if (ret != -EPIPE && ret != -ESTRPIPE) |
|---|
| 1260 | 1248 | break; |
|---|
| 1261 | 1249 | /* test, if we can't store new data, because the stream */ |
|---|
| .. | .. |
|---|
| 1291 | 1279 | ret = snd_pcm_oss_capture_position_fixup(substream, &delay); |
|---|
| 1292 | 1280 | if (ret < 0) |
|---|
| 1293 | 1281 | break; |
|---|
| 1282 | + mutex_unlock(&runtime->oss.params_lock); |
|---|
| 1294 | 1283 | ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true, |
|---|
| 1295 | 1284 | frames, in_kernel); |
|---|
| 1285 | + mutex_lock(&runtime->oss.params_lock); |
|---|
| 1296 | 1286 | if (ret == -EPIPE) { |
|---|
| 1297 | 1287 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { |
|---|
| 1298 | 1288 | ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); |
|---|
| .. | .. |
|---|
| 1672 | 1662 | runtime = substream->runtime; |
|---|
| 1673 | 1663 | if (atomic_read(&substream->mmap_count)) |
|---|
| 1674 | 1664 | goto __direct; |
|---|
| 1675 | | - if ((err = snd_pcm_oss_make_ready(substream)) < 0) |
|---|
| 1676 | | - return err; |
|---|
| 1677 | 1665 | atomic_inc(&runtime->oss.rw_ref); |
|---|
| 1678 | 1666 | if (mutex_lock_interruptible(&runtime->oss.params_lock)) { |
|---|
| 1679 | 1667 | atomic_dec(&runtime->oss.rw_ref); |
|---|
| 1680 | 1668 | return -ERESTARTSYS; |
|---|
| 1681 | 1669 | } |
|---|
| 1670 | + err = snd_pcm_oss_make_ready_locked(substream); |
|---|
| 1671 | + if (err < 0) |
|---|
| 1672 | + goto unlock; |
|---|
| 1682 | 1673 | format = snd_pcm_oss_format_from(runtime->oss.format); |
|---|
| 1683 | 1674 | width = snd_pcm_format_physical_width(format); |
|---|
| 1684 | 1675 | if (runtime->oss.buffer_used > 0) { |
|---|
| .. | .. |
|---|
| 2451 | 2442 | } |
|---|
| 2452 | 2443 | |
|---|
| 2453 | 2444 | pcm_oss_file->streams[idx] = substream; |
|---|
| 2454 | | - substream->file = pcm_oss_file; |
|---|
| 2455 | 2445 | snd_pcm_oss_init_substream(substream, &setup[idx], minor); |
|---|
| 2456 | 2446 | } |
|---|
| 2457 | 2447 | |
|---|
| .. | .. |
|---|
| 2756 | 2746 | static long snd_pcm_oss_ioctl_compat(struct file *file, unsigned int cmd, |
|---|
| 2757 | 2747 | unsigned long arg) |
|---|
| 2758 | 2748 | { |
|---|
| 2749 | + /* |
|---|
| 2750 | + * Everything is compatbile except SNDCTL_DSP_MAPINBUF/SNDCTL_DSP_MAPOUTBUF, |
|---|
| 2751 | + * which are not implemented for the native case either |
|---|
| 2752 | + */ |
|---|
| 2759 | 2753 | return snd_pcm_oss_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); |
|---|
| 2760 | 2754 | } |
|---|
| 2761 | 2755 | #else |
|---|
| .. | .. |
|---|
| 2885 | 2879 | substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; |
|---|
| 2886 | 2880 | if (substream) |
|---|
| 2887 | 2881 | break; |
|---|
| 2888 | | - /* Fall through */ |
|---|
| 2882 | + fallthrough; |
|---|
| 2889 | 2883 | case VM_READ: |
|---|
| 2890 | 2884 | substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; |
|---|
| 2891 | 2885 | break; |
|---|
| .. | .. |
|---|
| 2910 | 2904 | |
|---|
| 2911 | 2905 | if (runtime->oss.params) { |
|---|
| 2912 | 2906 | /* use mutex_trylock() for params_lock for avoiding a deadlock |
|---|
| 2913 | | - * between mmap_sem and params_lock taken by |
|---|
| 2907 | + * between mmap_lock and params_lock taken by |
|---|
| 2914 | 2908 | * copy_from/to_user() in snd_pcm_oss_write/read() |
|---|
| 2915 | 2909 | */ |
|---|
| 2916 | 2910 | err = snd_pcm_oss_change_params(substream, true); |
|---|