18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *   32bit -> 64bit ioctl wrapper for PCM API
48c2ecf20Sopenharmony_ci *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/* This file included from pcm_native.c */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/compat.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream,
138c2ecf20Sopenharmony_ci				      s32 __user *src)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	snd_pcm_sframes_t delay;
168c2ecf20Sopenharmony_ci	int err;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	err = snd_pcm_delay(substream, &delay);
198c2ecf20Sopenharmony_ci	if (err)
208c2ecf20Sopenharmony_ci		return err;
218c2ecf20Sopenharmony_ci	if (put_user(delay, src))
228c2ecf20Sopenharmony_ci		return -EFAULT;
238c2ecf20Sopenharmony_ci	return 0;
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream,
278c2ecf20Sopenharmony_ci				       u32 __user *src)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	snd_pcm_uframes_t frames;
308c2ecf20Sopenharmony_ci	int err;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	if (get_user(frames, src))
338c2ecf20Sopenharmony_ci		return -EFAULT;
348c2ecf20Sopenharmony_ci	err = snd_pcm_rewind(substream, frames);
358c2ecf20Sopenharmony_ci	if (put_user(err, src))
368c2ecf20Sopenharmony_ci		return -EFAULT;
378c2ecf20Sopenharmony_ci	return err < 0 ? err : 0;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic int snd_pcm_ioctl_forward_compat(struct snd_pcm_substream *substream,
418c2ecf20Sopenharmony_ci				       u32 __user *src)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	snd_pcm_uframes_t frames;
448c2ecf20Sopenharmony_ci	int err;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	if (get_user(frames, src))
478c2ecf20Sopenharmony_ci		return -EFAULT;
488c2ecf20Sopenharmony_ci	err = snd_pcm_forward(substream, frames);
498c2ecf20Sopenharmony_ci	if (put_user(err, src))
508c2ecf20Sopenharmony_ci		return -EFAULT;
518c2ecf20Sopenharmony_ci	return err < 0 ? err : 0;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistruct snd_pcm_hw_params32 {
558c2ecf20Sopenharmony_ci	u32 flags;
568c2ecf20Sopenharmony_ci	struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */
578c2ecf20Sopenharmony_ci	struct snd_mask mres[5];	/* reserved masks */
588c2ecf20Sopenharmony_ci	struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
598c2ecf20Sopenharmony_ci	struct snd_interval ires[9];	/* reserved intervals */
608c2ecf20Sopenharmony_ci	u32 rmask;
618c2ecf20Sopenharmony_ci	u32 cmask;
628c2ecf20Sopenharmony_ci	u32 info;
638c2ecf20Sopenharmony_ci	u32 msbits;
648c2ecf20Sopenharmony_ci	u32 rate_num;
658c2ecf20Sopenharmony_ci	u32 rate_den;
668c2ecf20Sopenharmony_ci	u32 fifo_size;
678c2ecf20Sopenharmony_ci	unsigned char reserved[64];
688c2ecf20Sopenharmony_ci};
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistruct snd_pcm_sw_params32 {
718c2ecf20Sopenharmony_ci	s32 tstamp_mode;
728c2ecf20Sopenharmony_ci	u32 period_step;
738c2ecf20Sopenharmony_ci	u32 sleep_min;
748c2ecf20Sopenharmony_ci	u32 avail_min;
758c2ecf20Sopenharmony_ci	u32 xfer_align;
768c2ecf20Sopenharmony_ci	u32 start_threshold;
778c2ecf20Sopenharmony_ci	u32 stop_threshold;
788c2ecf20Sopenharmony_ci	u32 silence_threshold;
798c2ecf20Sopenharmony_ci	u32 silence_size;
808c2ecf20Sopenharmony_ci	u32 boundary;
818c2ecf20Sopenharmony_ci	u32 proto;
828c2ecf20Sopenharmony_ci	u32 tstamp_type;
838c2ecf20Sopenharmony_ci	unsigned char reserved[56];
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream,
878c2ecf20Sopenharmony_ci					  struct snd_pcm_sw_params32 __user *src)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	struct snd_pcm_sw_params params;
908c2ecf20Sopenharmony_ci	snd_pcm_uframes_t boundary;
918c2ecf20Sopenharmony_ci	int err;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	memset(&params, 0, sizeof(params));
948c2ecf20Sopenharmony_ci	if (get_user(params.tstamp_mode, &src->tstamp_mode) ||
958c2ecf20Sopenharmony_ci	    get_user(params.period_step, &src->period_step) ||
968c2ecf20Sopenharmony_ci	    get_user(params.sleep_min, &src->sleep_min) ||
978c2ecf20Sopenharmony_ci	    get_user(params.avail_min, &src->avail_min) ||
988c2ecf20Sopenharmony_ci	    get_user(params.xfer_align, &src->xfer_align) ||
998c2ecf20Sopenharmony_ci	    get_user(params.start_threshold, &src->start_threshold) ||
1008c2ecf20Sopenharmony_ci	    get_user(params.stop_threshold, &src->stop_threshold) ||
1018c2ecf20Sopenharmony_ci	    get_user(params.silence_threshold, &src->silence_threshold) ||
1028c2ecf20Sopenharmony_ci	    get_user(params.silence_size, &src->silence_size) ||
1038c2ecf20Sopenharmony_ci	    get_user(params.tstamp_type, &src->tstamp_type) ||
1048c2ecf20Sopenharmony_ci	    get_user(params.proto, &src->proto))
1058c2ecf20Sopenharmony_ci		return -EFAULT;
1068c2ecf20Sopenharmony_ci	/*
1078c2ecf20Sopenharmony_ci	 * Check silent_size parameter.  Since we have 64bit boundary,
1088c2ecf20Sopenharmony_ci	 * silence_size must be compared with the 32bit boundary.
1098c2ecf20Sopenharmony_ci	 */
1108c2ecf20Sopenharmony_ci	boundary = recalculate_boundary(substream->runtime);
1118c2ecf20Sopenharmony_ci	if (boundary && params.silence_size >= boundary)
1128c2ecf20Sopenharmony_ci		params.silence_size = substream->runtime->boundary;
1138c2ecf20Sopenharmony_ci	err = snd_pcm_sw_params(substream, &params);
1148c2ecf20Sopenharmony_ci	if (err < 0)
1158c2ecf20Sopenharmony_ci		return err;
1168c2ecf20Sopenharmony_ci	if (boundary && put_user(boundary, &src->boundary))
1178c2ecf20Sopenharmony_ci		return -EFAULT;
1188c2ecf20Sopenharmony_ci	return err;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistruct snd_pcm_channel_info32 {
1228c2ecf20Sopenharmony_ci	u32 channel;
1238c2ecf20Sopenharmony_ci	u32 offset;
1248c2ecf20Sopenharmony_ci	u32 first;
1258c2ecf20Sopenharmony_ci	u32 step;
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream,
1298c2ecf20Sopenharmony_ci					     struct snd_pcm_channel_info32 __user *src)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	struct snd_pcm_channel_info info;
1328c2ecf20Sopenharmony_ci	int err;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (get_user(info.channel, &src->channel) ||
1358c2ecf20Sopenharmony_ci	    get_user(info.offset, &src->offset) ||
1368c2ecf20Sopenharmony_ci	    get_user(info.first, &src->first) ||
1378c2ecf20Sopenharmony_ci	    get_user(info.step, &src->step))
1388c2ecf20Sopenharmony_ci		return -EFAULT;
1398c2ecf20Sopenharmony_ci	err = snd_pcm_channel_info(substream, &info);
1408c2ecf20Sopenharmony_ci	if (err < 0)
1418c2ecf20Sopenharmony_ci		return err;
1428c2ecf20Sopenharmony_ci	if (put_user(info.channel, &src->channel) ||
1438c2ecf20Sopenharmony_ci	    put_user(info.offset, &src->offset) ||
1448c2ecf20Sopenharmony_ci	    put_user(info.first, &src->first) ||
1458c2ecf20Sopenharmony_ci	    put_user(info.step, &src->step))
1468c2ecf20Sopenharmony_ci		return -EFAULT;
1478c2ecf20Sopenharmony_ci	return err;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_X32
1518c2ecf20Sopenharmony_ci/* X32 ABI has the same struct as x86-64 for snd_pcm_channel_info */
1528c2ecf20Sopenharmony_cistatic int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
1538c2ecf20Sopenharmony_ci				     struct snd_pcm_channel_info __user *src);
1548c2ecf20Sopenharmony_ci#define snd_pcm_ioctl_channel_info_x32(s, p)	\
1558c2ecf20Sopenharmony_ci	snd_pcm_channel_info_user(s, p)
1568c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_X32 */
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistruct compat_snd_pcm_status64 {
1598c2ecf20Sopenharmony_ci	snd_pcm_state_t state;
1608c2ecf20Sopenharmony_ci	u8 rsvd[4]; /* alignment */
1618c2ecf20Sopenharmony_ci	s64 trigger_tstamp_sec;
1628c2ecf20Sopenharmony_ci	s64 trigger_tstamp_nsec;
1638c2ecf20Sopenharmony_ci	s64 tstamp_sec;
1648c2ecf20Sopenharmony_ci	s64 tstamp_nsec;
1658c2ecf20Sopenharmony_ci	u32 appl_ptr;
1668c2ecf20Sopenharmony_ci	u32 hw_ptr;
1678c2ecf20Sopenharmony_ci	s32 delay;
1688c2ecf20Sopenharmony_ci	u32 avail;
1698c2ecf20Sopenharmony_ci	u32 avail_max;
1708c2ecf20Sopenharmony_ci	u32 overrange;
1718c2ecf20Sopenharmony_ci	snd_pcm_state_t suspended_state;
1728c2ecf20Sopenharmony_ci	u32 audio_tstamp_data;
1738c2ecf20Sopenharmony_ci	s64 audio_tstamp_sec;
1748c2ecf20Sopenharmony_ci	s64 audio_tstamp_nsec;
1758c2ecf20Sopenharmony_ci	s64 driver_tstamp_sec;
1768c2ecf20Sopenharmony_ci	s64 driver_tstamp_nsec;
1778c2ecf20Sopenharmony_ci	u32 audio_tstamp_accuracy;
1788c2ecf20Sopenharmony_ci	unsigned char reserved[52-4*sizeof(s64)];
1798c2ecf20Sopenharmony_ci} __packed;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int snd_pcm_status_user_compat64(struct snd_pcm_substream *substream,
1828c2ecf20Sopenharmony_ci					struct compat_snd_pcm_status64 __user *src,
1838c2ecf20Sopenharmony_ci					bool ext)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	struct snd_pcm_status64 status;
1868c2ecf20Sopenharmony_ci	struct compat_snd_pcm_status64 compat_status64;
1878c2ecf20Sopenharmony_ci	int err;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	memset(&status, 0, sizeof(status));
1908c2ecf20Sopenharmony_ci	memset(&compat_status64, 0, sizeof(compat_status64));
1918c2ecf20Sopenharmony_ci	/*
1928c2ecf20Sopenharmony_ci	 * with extension, parameters are read/write,
1938c2ecf20Sopenharmony_ci	 * get audio_tstamp_data from user,
1948c2ecf20Sopenharmony_ci	 * ignore rest of status structure
1958c2ecf20Sopenharmony_ci	 */
1968c2ecf20Sopenharmony_ci	if (ext && get_user(status.audio_tstamp_data,
1978c2ecf20Sopenharmony_ci				(u32 __user *)(&src->audio_tstamp_data)))
1988c2ecf20Sopenharmony_ci		return -EFAULT;
1998c2ecf20Sopenharmony_ci	err = snd_pcm_status64(substream, &status);
2008c2ecf20Sopenharmony_ci	if (err < 0)
2018c2ecf20Sopenharmony_ci		return err;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (clear_user(src, sizeof(*src)))
2048c2ecf20Sopenharmony_ci		return -EFAULT;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	compat_status64 = (struct compat_snd_pcm_status64) {
2078c2ecf20Sopenharmony_ci		.state = status.state,
2088c2ecf20Sopenharmony_ci		.trigger_tstamp_sec = status.trigger_tstamp_sec,
2098c2ecf20Sopenharmony_ci		.trigger_tstamp_nsec = status.trigger_tstamp_nsec,
2108c2ecf20Sopenharmony_ci		.tstamp_sec = status.tstamp_sec,
2118c2ecf20Sopenharmony_ci		.tstamp_nsec = status.tstamp_nsec,
2128c2ecf20Sopenharmony_ci		.appl_ptr = status.appl_ptr,
2138c2ecf20Sopenharmony_ci		.hw_ptr = status.hw_ptr,
2148c2ecf20Sopenharmony_ci		.delay = status.delay,
2158c2ecf20Sopenharmony_ci		.avail = status.avail,
2168c2ecf20Sopenharmony_ci		.avail_max = status.avail_max,
2178c2ecf20Sopenharmony_ci		.overrange = status.overrange,
2188c2ecf20Sopenharmony_ci		.suspended_state = status.suspended_state,
2198c2ecf20Sopenharmony_ci		.audio_tstamp_data = status.audio_tstamp_data,
2208c2ecf20Sopenharmony_ci		.audio_tstamp_sec = status.audio_tstamp_sec,
2218c2ecf20Sopenharmony_ci		.audio_tstamp_nsec = status.audio_tstamp_nsec,
2228c2ecf20Sopenharmony_ci		.driver_tstamp_sec = status.audio_tstamp_sec,
2238c2ecf20Sopenharmony_ci		.driver_tstamp_nsec = status.audio_tstamp_nsec,
2248c2ecf20Sopenharmony_ci		.audio_tstamp_accuracy = status.audio_tstamp_accuracy,
2258c2ecf20Sopenharmony_ci	};
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	if (copy_to_user(src, &compat_status64, sizeof(compat_status64)))
2288c2ecf20Sopenharmony_ci		return -EFAULT;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	return err;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/* both for HW_PARAMS and HW_REFINE */
2348c2ecf20Sopenharmony_cistatic int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
2358c2ecf20Sopenharmony_ci					  int refine,
2368c2ecf20Sopenharmony_ci					  struct snd_pcm_hw_params32 __user *data32)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct snd_pcm_hw_params *data;
2398c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime;
2408c2ecf20Sopenharmony_ci	int err;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (! (runtime = substream->runtime))
2438c2ecf20Sopenharmony_ci		return -ENOTTY;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	data = kmalloc(sizeof(*data), GFP_KERNEL);
2468c2ecf20Sopenharmony_ci	if (!data)
2478c2ecf20Sopenharmony_ci		return -ENOMEM;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	/* only fifo_size (RO from userspace) is different, so just copy all */
2508c2ecf20Sopenharmony_ci	if (copy_from_user(data, data32, sizeof(*data32))) {
2518c2ecf20Sopenharmony_ci		err = -EFAULT;
2528c2ecf20Sopenharmony_ci		goto error;
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if (refine) {
2568c2ecf20Sopenharmony_ci		err = snd_pcm_hw_refine(substream, data);
2578c2ecf20Sopenharmony_ci		if (err < 0)
2588c2ecf20Sopenharmony_ci			goto error;
2598c2ecf20Sopenharmony_ci		err = fixup_unreferenced_params(substream, data);
2608c2ecf20Sopenharmony_ci	} else {
2618c2ecf20Sopenharmony_ci		err = snd_pcm_hw_params(substream, data);
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci	if (err < 0)
2648c2ecf20Sopenharmony_ci		goto error;
2658c2ecf20Sopenharmony_ci	if (copy_to_user(data32, data, sizeof(*data32)) ||
2668c2ecf20Sopenharmony_ci	    put_user(data->fifo_size, &data32->fifo_size)) {
2678c2ecf20Sopenharmony_ci		err = -EFAULT;
2688c2ecf20Sopenharmony_ci		goto error;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (! refine) {
2728c2ecf20Sopenharmony_ci		unsigned int new_boundary = recalculate_boundary(runtime);
2738c2ecf20Sopenharmony_ci		if (new_boundary)
2748c2ecf20Sopenharmony_ci			runtime->boundary = new_boundary;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci error:
2778c2ecf20Sopenharmony_ci	kfree(data);
2788c2ecf20Sopenharmony_ci	return err;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci/*
2838c2ecf20Sopenharmony_ci */
2848c2ecf20Sopenharmony_cistruct snd_xferi32 {
2858c2ecf20Sopenharmony_ci	s32 result;
2868c2ecf20Sopenharmony_ci	u32 buf;
2878c2ecf20Sopenharmony_ci	u32 frames;
2888c2ecf20Sopenharmony_ci};
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic int snd_pcm_ioctl_xferi_compat(struct snd_pcm_substream *substream,
2918c2ecf20Sopenharmony_ci				      int dir, struct snd_xferi32 __user *data32)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	compat_caddr_t buf;
2948c2ecf20Sopenharmony_ci	u32 frames;
2958c2ecf20Sopenharmony_ci	int err;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	if (! substream->runtime)
2988c2ecf20Sopenharmony_ci		return -ENOTTY;
2998c2ecf20Sopenharmony_ci	if (substream->stream != dir)
3008c2ecf20Sopenharmony_ci		return -EINVAL;
3018c2ecf20Sopenharmony_ci	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
3028c2ecf20Sopenharmony_ci		return -EBADFD;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (get_user(buf, &data32->buf) ||
3058c2ecf20Sopenharmony_ci	    get_user(frames, &data32->frames))
3068c2ecf20Sopenharmony_ci		return -EFAULT;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
3098c2ecf20Sopenharmony_ci		err = snd_pcm_lib_write(substream, compat_ptr(buf), frames);
3108c2ecf20Sopenharmony_ci	else
3118c2ecf20Sopenharmony_ci		err = snd_pcm_lib_read(substream, compat_ptr(buf), frames);
3128c2ecf20Sopenharmony_ci	if (err < 0)
3138c2ecf20Sopenharmony_ci		return err;
3148c2ecf20Sopenharmony_ci	/* copy the result */
3158c2ecf20Sopenharmony_ci	if (put_user(err, &data32->result))
3168c2ecf20Sopenharmony_ci		return -EFAULT;
3178c2ecf20Sopenharmony_ci	return 0;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci/* snd_xfern needs remapping of bufs */
3228c2ecf20Sopenharmony_cistruct snd_xfern32 {
3238c2ecf20Sopenharmony_ci	s32 result;
3248c2ecf20Sopenharmony_ci	u32 bufs;  /* this is void **; */
3258c2ecf20Sopenharmony_ci	u32 frames;
3268c2ecf20Sopenharmony_ci};
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci/*
3298c2ecf20Sopenharmony_ci * xfern ioctl nees to copy (up to) 128 pointers on stack.
3308c2ecf20Sopenharmony_ci * although we may pass the copied pointers through f_op->ioctl, but the ioctl
3318c2ecf20Sopenharmony_ci * handler there expands again the same 128 pointers on stack, so it is better
3328c2ecf20Sopenharmony_ci * to handle the function (calling pcm_readv/writev) directly in this handler.
3338c2ecf20Sopenharmony_ci */
3348c2ecf20Sopenharmony_cistatic int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
3358c2ecf20Sopenharmony_ci				      int dir, struct snd_xfern32 __user *data32)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	compat_caddr_t buf;
3388c2ecf20Sopenharmony_ci	compat_caddr_t __user *bufptr;
3398c2ecf20Sopenharmony_ci	u32 frames;
3408c2ecf20Sopenharmony_ci	void __user **bufs;
3418c2ecf20Sopenharmony_ci	int err, ch, i;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (! substream->runtime)
3448c2ecf20Sopenharmony_ci		return -ENOTTY;
3458c2ecf20Sopenharmony_ci	if (substream->stream != dir)
3468c2ecf20Sopenharmony_ci		return -EINVAL;
3478c2ecf20Sopenharmony_ci	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
3488c2ecf20Sopenharmony_ci		return -EBADFD;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if ((ch = substream->runtime->channels) > 128)
3518c2ecf20Sopenharmony_ci		return -EINVAL;
3528c2ecf20Sopenharmony_ci	if (get_user(buf, &data32->bufs) ||
3538c2ecf20Sopenharmony_ci	    get_user(frames, &data32->frames))
3548c2ecf20Sopenharmony_ci		return -EFAULT;
3558c2ecf20Sopenharmony_ci	bufptr = compat_ptr(buf);
3568c2ecf20Sopenharmony_ci	bufs = kmalloc_array(ch, sizeof(void __user *), GFP_KERNEL);
3578c2ecf20Sopenharmony_ci	if (bufs == NULL)
3588c2ecf20Sopenharmony_ci		return -ENOMEM;
3598c2ecf20Sopenharmony_ci	for (i = 0; i < ch; i++) {
3608c2ecf20Sopenharmony_ci		u32 ptr;
3618c2ecf20Sopenharmony_ci		if (get_user(ptr, bufptr)) {
3628c2ecf20Sopenharmony_ci			kfree(bufs);
3638c2ecf20Sopenharmony_ci			return -EFAULT;
3648c2ecf20Sopenharmony_ci		}
3658c2ecf20Sopenharmony_ci		bufs[i] = compat_ptr(ptr);
3668c2ecf20Sopenharmony_ci		bufptr++;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
3698c2ecf20Sopenharmony_ci		err = snd_pcm_lib_writev(substream, bufs, frames);
3708c2ecf20Sopenharmony_ci	else
3718c2ecf20Sopenharmony_ci		err = snd_pcm_lib_readv(substream, bufs, frames);
3728c2ecf20Sopenharmony_ci	if (err >= 0) {
3738c2ecf20Sopenharmony_ci		if (put_user(err, &data32->result))
3748c2ecf20Sopenharmony_ci			err = -EFAULT;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci	kfree(bufs);
3778c2ecf20Sopenharmony_ci	return err;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_X32
3818c2ecf20Sopenharmony_ci/* X32 ABI has 64bit timespec and 64bit alignment */
3828c2ecf20Sopenharmony_cistruct snd_pcm_mmap_status_x32 {
3838c2ecf20Sopenharmony_ci	snd_pcm_state_t state;
3848c2ecf20Sopenharmony_ci	s32 pad1;
3858c2ecf20Sopenharmony_ci	u32 hw_ptr;
3868c2ecf20Sopenharmony_ci	u32 pad2; /* alignment */
3878c2ecf20Sopenharmony_ci	s64 tstamp_sec;
3888c2ecf20Sopenharmony_ci	s64 tstamp_nsec;
3898c2ecf20Sopenharmony_ci	snd_pcm_state_t suspended_state;
3908c2ecf20Sopenharmony_ci	s32 pad3;
3918c2ecf20Sopenharmony_ci	s64 audio_tstamp_sec;
3928c2ecf20Sopenharmony_ci	s64 audio_tstamp_nsec;
3938c2ecf20Sopenharmony_ci} __packed;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistruct snd_pcm_mmap_control_x32 {
3968c2ecf20Sopenharmony_ci	u32 appl_ptr;
3978c2ecf20Sopenharmony_ci	u32 avail_min;
3988c2ecf20Sopenharmony_ci};
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistruct snd_pcm_sync_ptr_x32 {
4018c2ecf20Sopenharmony_ci	u32 flags;
4028c2ecf20Sopenharmony_ci	u32 rsvd; /* alignment */
4038c2ecf20Sopenharmony_ci	union {
4048c2ecf20Sopenharmony_ci		struct snd_pcm_mmap_status_x32 status;
4058c2ecf20Sopenharmony_ci		unsigned char reserved[64];
4068c2ecf20Sopenharmony_ci	} s;
4078c2ecf20Sopenharmony_ci	union {
4088c2ecf20Sopenharmony_ci		struct snd_pcm_mmap_control_x32 control;
4098c2ecf20Sopenharmony_ci		unsigned char reserved[64];
4108c2ecf20Sopenharmony_ci	} c;
4118c2ecf20Sopenharmony_ci} __packed;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
4148c2ecf20Sopenharmony_ci				      struct snd_pcm_sync_ptr_x32 __user *src)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
4178c2ecf20Sopenharmony_ci	volatile struct snd_pcm_mmap_status *status;
4188c2ecf20Sopenharmony_ci	volatile struct snd_pcm_mmap_control *control;
4198c2ecf20Sopenharmony_ci	u32 sflags;
4208c2ecf20Sopenharmony_ci	struct snd_pcm_mmap_control scontrol;
4218c2ecf20Sopenharmony_ci	struct snd_pcm_mmap_status sstatus;
4228c2ecf20Sopenharmony_ci	snd_pcm_uframes_t boundary;
4238c2ecf20Sopenharmony_ci	int err;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!runtime))
4268c2ecf20Sopenharmony_ci		return -EINVAL;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	if (get_user(sflags, &src->flags) ||
4298c2ecf20Sopenharmony_ci	    get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
4308c2ecf20Sopenharmony_ci	    get_user(scontrol.avail_min, &src->c.control.avail_min))
4318c2ecf20Sopenharmony_ci		return -EFAULT;
4328c2ecf20Sopenharmony_ci	if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
4338c2ecf20Sopenharmony_ci		err = snd_pcm_hwsync(substream);
4348c2ecf20Sopenharmony_ci		if (err < 0)
4358c2ecf20Sopenharmony_ci			return err;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci	status = runtime->status;
4388c2ecf20Sopenharmony_ci	control = runtime->control;
4398c2ecf20Sopenharmony_ci	boundary = recalculate_boundary(runtime);
4408c2ecf20Sopenharmony_ci	if (!boundary)
4418c2ecf20Sopenharmony_ci		boundary = 0x7fffffff;
4428c2ecf20Sopenharmony_ci	snd_pcm_stream_lock_irq(substream);
4438c2ecf20Sopenharmony_ci	/* FIXME: we should consider the boundary for the sync from app */
4448c2ecf20Sopenharmony_ci	if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
4458c2ecf20Sopenharmony_ci		control->appl_ptr = scontrol.appl_ptr;
4468c2ecf20Sopenharmony_ci	else
4478c2ecf20Sopenharmony_ci		scontrol.appl_ptr = control->appl_ptr % boundary;
4488c2ecf20Sopenharmony_ci	if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
4498c2ecf20Sopenharmony_ci		control->avail_min = scontrol.avail_min;
4508c2ecf20Sopenharmony_ci	else
4518c2ecf20Sopenharmony_ci		scontrol.avail_min = control->avail_min;
4528c2ecf20Sopenharmony_ci	sstatus.state = status->state;
4538c2ecf20Sopenharmony_ci	sstatus.hw_ptr = status->hw_ptr % boundary;
4548c2ecf20Sopenharmony_ci	sstatus.tstamp = status->tstamp;
4558c2ecf20Sopenharmony_ci	sstatus.suspended_state = status->suspended_state;
4568c2ecf20Sopenharmony_ci	sstatus.audio_tstamp = status->audio_tstamp;
4578c2ecf20Sopenharmony_ci	snd_pcm_stream_unlock_irq(substream);
4588c2ecf20Sopenharmony_ci	if (put_user(sstatus.state, &src->s.status.state) ||
4598c2ecf20Sopenharmony_ci	    put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
4608c2ecf20Sopenharmony_ci	    put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) ||
4618c2ecf20Sopenharmony_ci	    put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp_nsec) ||
4628c2ecf20Sopenharmony_ci	    put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
4638c2ecf20Sopenharmony_ci	    put_user(sstatus.audio_tstamp.tv_sec, &src->s.status.audio_tstamp_sec) ||
4648c2ecf20Sopenharmony_ci	    put_user(sstatus.audio_tstamp.tv_nsec, &src->s.status.audio_tstamp_nsec) ||
4658c2ecf20Sopenharmony_ci	    put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
4668c2ecf20Sopenharmony_ci	    put_user(scontrol.avail_min, &src->c.control.avail_min))
4678c2ecf20Sopenharmony_ci		return -EFAULT;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	return 0;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_X32 */
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
4748c2ecf20Sopenharmony_citypedef char __pad_before_u32[4];
4758c2ecf20Sopenharmony_citypedef char __pad_after_u32[0];
4768c2ecf20Sopenharmony_ci#else
4778c2ecf20Sopenharmony_citypedef char __pad_before_u32[0];
4788c2ecf20Sopenharmony_citypedef char __pad_after_u32[4];
4798c2ecf20Sopenharmony_ci#endif
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/* PCM 2.0.15 API definition had a bug in mmap control; it puts the avail_min
4828c2ecf20Sopenharmony_ci * at the wrong offset due to a typo in padding type.
4838c2ecf20Sopenharmony_ci * The bug hits only 32bit.
4848c2ecf20Sopenharmony_ci * A workaround for incorrect read/write is needed only in 32bit compat mode.
4858c2ecf20Sopenharmony_ci */
4868c2ecf20Sopenharmony_cistruct __snd_pcm_mmap_control64_buggy {
4878c2ecf20Sopenharmony_ci	__pad_before_u32 __pad1;
4888c2ecf20Sopenharmony_ci	__u32 appl_ptr;
4898c2ecf20Sopenharmony_ci	__pad_before_u32 __pad2;	/* SiC! here is the bug */
4908c2ecf20Sopenharmony_ci	__pad_before_u32 __pad3;
4918c2ecf20Sopenharmony_ci	__u32 avail_min;
4928c2ecf20Sopenharmony_ci	__pad_after_uframe __pad4;
4938c2ecf20Sopenharmony_ci};
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream,
4968c2ecf20Sopenharmony_ci					struct snd_pcm_sync_ptr __user *_sync_ptr)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
4998c2ecf20Sopenharmony_ci	struct snd_pcm_sync_ptr sync_ptr;
5008c2ecf20Sopenharmony_ci	struct __snd_pcm_mmap_control64_buggy *sync_cp;
5018c2ecf20Sopenharmony_ci	volatile struct snd_pcm_mmap_status *status;
5028c2ecf20Sopenharmony_ci	volatile struct snd_pcm_mmap_control *control;
5038c2ecf20Sopenharmony_ci	int err;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	memset(&sync_ptr, 0, sizeof(sync_ptr));
5068c2ecf20Sopenharmony_ci	sync_cp = (struct __snd_pcm_mmap_control64_buggy *)&sync_ptr.c.control;
5078c2ecf20Sopenharmony_ci	if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags)))
5088c2ecf20Sopenharmony_ci		return -EFAULT;
5098c2ecf20Sopenharmony_ci	if (copy_from_user(sync_cp, &(_sync_ptr->c.control), sizeof(*sync_cp)))
5108c2ecf20Sopenharmony_ci		return -EFAULT;
5118c2ecf20Sopenharmony_ci	status = runtime->status;
5128c2ecf20Sopenharmony_ci	control = runtime->control;
5138c2ecf20Sopenharmony_ci	if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
5148c2ecf20Sopenharmony_ci		err = snd_pcm_hwsync(substream);
5158c2ecf20Sopenharmony_ci		if (err < 0)
5168c2ecf20Sopenharmony_ci			return err;
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci	snd_pcm_stream_lock_irq(substream);
5198c2ecf20Sopenharmony_ci	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
5208c2ecf20Sopenharmony_ci		err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
5218c2ecf20Sopenharmony_ci		if (err < 0) {
5228c2ecf20Sopenharmony_ci			snd_pcm_stream_unlock_irq(substream);
5238c2ecf20Sopenharmony_ci			return err;
5248c2ecf20Sopenharmony_ci		}
5258c2ecf20Sopenharmony_ci	} else {
5268c2ecf20Sopenharmony_ci		sync_cp->appl_ptr = control->appl_ptr;
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
5298c2ecf20Sopenharmony_ci		control->avail_min = sync_cp->avail_min;
5308c2ecf20Sopenharmony_ci	else
5318c2ecf20Sopenharmony_ci		sync_cp->avail_min = control->avail_min;
5328c2ecf20Sopenharmony_ci	sync_ptr.s.status.state = status->state;
5338c2ecf20Sopenharmony_ci	sync_ptr.s.status.hw_ptr = status->hw_ptr;
5348c2ecf20Sopenharmony_ci	sync_ptr.s.status.tstamp = status->tstamp;
5358c2ecf20Sopenharmony_ci	sync_ptr.s.status.suspended_state = status->suspended_state;
5368c2ecf20Sopenharmony_ci	sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
5378c2ecf20Sopenharmony_ci	snd_pcm_stream_unlock_irq(substream);
5388c2ecf20Sopenharmony_ci	if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
5398c2ecf20Sopenharmony_ci		return -EFAULT;
5408c2ecf20Sopenharmony_ci	return 0;
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci/*
5448c2ecf20Sopenharmony_ci */
5458c2ecf20Sopenharmony_cienum {
5468c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct snd_pcm_hw_params32),
5478c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
5488c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
5498c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_STATUS_COMPAT32 = _IOR('A', 0x20, struct snd_pcm_status32),
5508c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32 = _IOWR('A', 0x24, struct snd_pcm_status32),
5518c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
5528c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
5538c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
5548c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_FORWARD32 = _IOW('A', 0x49, u32),
5558c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct snd_xferi32),
5568c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct snd_xferi32),
5578c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32),
5588c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32),
5598c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_STATUS_COMPAT64 = _IOR('A', 0x20, struct compat_snd_pcm_status64),
5608c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64 = _IOWR('A', 0x24, struct compat_snd_pcm_status64),
5618c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_X32
5628c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info),
5638c2ecf20Sopenharmony_ci	SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32),
5648c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_X32 */
5658c2ecf20Sopenharmony_ci};
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	struct snd_pcm_file *pcm_file;
5708c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream;
5718c2ecf20Sopenharmony_ci	void __user *argp = compat_ptr(arg);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	pcm_file = file->private_data;
5748c2ecf20Sopenharmony_ci	if (! pcm_file)
5758c2ecf20Sopenharmony_ci		return -ENOTTY;
5768c2ecf20Sopenharmony_ci	substream = pcm_file->substream;
5778c2ecf20Sopenharmony_ci	if (! substream)
5788c2ecf20Sopenharmony_ci		return -ENOTTY;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	/*
5818c2ecf20Sopenharmony_ci	 * When PCM is used on 32bit mode, we need to disable
5828c2ecf20Sopenharmony_ci	 * mmap of the old PCM status/control records because
5838c2ecf20Sopenharmony_ci	 * of the size incompatibility.
5848c2ecf20Sopenharmony_ci	 */
5858c2ecf20Sopenharmony_ci	pcm_file->no_compat_mmap = 1;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	switch (cmd) {
5888c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_PVERSION:
5898c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_INFO:
5908c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_TSTAMP:
5918c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_TTSTAMP:
5928c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_USER_PVERSION:
5938c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_HWSYNC:
5948c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_PREPARE:
5958c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_RESET:
5968c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_START:
5978c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_DROP:
5988c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_DRAIN:
5998c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_PAUSE:
6008c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_HW_FREE:
6018c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_RESUME:
6028c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_XRUN:
6038c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_LINK:
6048c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_UNLINK:
6058c2ecf20Sopenharmony_ci	case __SNDRV_PCM_IOCTL_SYNC_PTR32:
6068c2ecf20Sopenharmony_ci		return snd_pcm_common_ioctl(file, substream, cmd, argp);
6078c2ecf20Sopenharmony_ci	case __SNDRV_PCM_IOCTL_SYNC_PTR64:
6088c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_X32
6098c2ecf20Sopenharmony_ci		if (in_x32_syscall())
6108c2ecf20Sopenharmony_ci			return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
6118c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_X32 */
6128c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_sync_ptr_buggy(substream, argp);
6138c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_HW_REFINE32:
6148c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
6158c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_HW_PARAMS32:
6168c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_hw_params_compat(substream, 0, argp);
6178c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_SW_PARAMS32:
6188c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_sw_params_compat(substream, argp);
6198c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_STATUS_COMPAT32:
6208c2ecf20Sopenharmony_ci		return snd_pcm_status_user32(substream, argp, false);
6218c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32:
6228c2ecf20Sopenharmony_ci		return snd_pcm_status_user32(substream, argp, true);
6238c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_CHANNEL_INFO32:
6248c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_channel_info_compat(substream, argp);
6258c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_WRITEI_FRAMES32:
6268c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
6278c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_READI_FRAMES32:
6288c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
6298c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_WRITEN_FRAMES32:
6308c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
6318c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_READN_FRAMES32:
6328c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
6338c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_DELAY32:
6348c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_delay_compat(substream, argp);
6358c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_REWIND32:
6368c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_rewind_compat(substream, argp);
6378c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_FORWARD32:
6388c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_forward_compat(substream, argp);
6398c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_STATUS_COMPAT64:
6408c2ecf20Sopenharmony_ci		return snd_pcm_status_user_compat64(substream, argp, false);
6418c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64:
6428c2ecf20Sopenharmony_ci		return snd_pcm_status_user_compat64(substream, argp, true);
6438c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_X32
6448c2ecf20Sopenharmony_ci	case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32:
6458c2ecf20Sopenharmony_ci		return snd_pcm_ioctl_channel_info_x32(substream, argp);
6468c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_X32 */
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	return -ENOIOCTLCMD;
6508c2ecf20Sopenharmony_ci}
651