.. | .. |
---|
| 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); |
---|