18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *   32bit -> 64bit ioctl wrapper for timer API
48c2ecf20Sopenharmony_ci *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/* This file included from timer.c */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/compat.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci * ILP32/LP64 has different size for 'long' type. Additionally, the size
138c2ecf20Sopenharmony_ci * of storage alignment differs depending on architectures. Here, '__packed'
148c2ecf20Sopenharmony_ci * qualifier is used so that the size of this structure is multiple of 4 and
158c2ecf20Sopenharmony_ci * it fits to any architectures with 32 bit storage alignment.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_cistruct snd_timer_gparams32 {
188c2ecf20Sopenharmony_ci	struct snd_timer_id tid;
198c2ecf20Sopenharmony_ci	u32 period_num;
208c2ecf20Sopenharmony_ci	u32 period_den;
218c2ecf20Sopenharmony_ci	unsigned char reserved[32];
228c2ecf20Sopenharmony_ci} __packed;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistruct snd_timer_info32 {
258c2ecf20Sopenharmony_ci	u32 flags;
268c2ecf20Sopenharmony_ci	s32 card;
278c2ecf20Sopenharmony_ci	unsigned char id[64];
288c2ecf20Sopenharmony_ci	unsigned char name[80];
298c2ecf20Sopenharmony_ci	u32 reserved0;
308c2ecf20Sopenharmony_ci	u32 resolution;
318c2ecf20Sopenharmony_ci	unsigned char reserved[64];
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic int snd_timer_user_gparams_compat(struct file *file,
358c2ecf20Sopenharmony_ci					struct snd_timer_gparams32 __user *user)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	struct snd_timer_gparams gparams;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (copy_from_user(&gparams.tid, &user->tid, sizeof(gparams.tid)) ||
408c2ecf20Sopenharmony_ci	    get_user(gparams.period_num, &user->period_num) ||
418c2ecf20Sopenharmony_ci	    get_user(gparams.period_den, &user->period_den))
428c2ecf20Sopenharmony_ci		return -EFAULT;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	return timer_set_gparams(&gparams);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic int snd_timer_user_info_compat(struct file *file,
488c2ecf20Sopenharmony_ci				      struct snd_timer_info32 __user *_info)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct snd_timer_user *tu;
518c2ecf20Sopenharmony_ci	struct snd_timer_info32 info;
528c2ecf20Sopenharmony_ci	struct snd_timer *t;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	tu = file->private_data;
558c2ecf20Sopenharmony_ci	if (!tu->timeri)
568c2ecf20Sopenharmony_ci		return -EBADFD;
578c2ecf20Sopenharmony_ci	t = tu->timeri->timer;
588c2ecf20Sopenharmony_ci	if (!t)
598c2ecf20Sopenharmony_ci		return -EBADFD;
608c2ecf20Sopenharmony_ci	memset(&info, 0, sizeof(info));
618c2ecf20Sopenharmony_ci	info.card = t->card ? t->card->number : -1;
628c2ecf20Sopenharmony_ci	if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
638c2ecf20Sopenharmony_ci		info.flags |= SNDRV_TIMER_FLG_SLAVE;
648c2ecf20Sopenharmony_ci	strlcpy(info.id, t->id, sizeof(info.id));
658c2ecf20Sopenharmony_ci	strlcpy(info.name, t->name, sizeof(info.name));
668c2ecf20Sopenharmony_ci	info.resolution = t->hw.resolution;
678c2ecf20Sopenharmony_ci	if (copy_to_user(_info, &info, sizeof(*_info)))
688c2ecf20Sopenharmony_ci		return -EFAULT;
698c2ecf20Sopenharmony_ci	return 0;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cienum {
738c2ecf20Sopenharmony_ci	SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32),
748c2ecf20Sopenharmony_ci	SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32),
758c2ecf20Sopenharmony_ci	SNDRV_TIMER_IOCTL_STATUS_COMPAT32 = _IOW('T', 0x14, struct snd_timer_status32),
768c2ecf20Sopenharmony_ci	SNDRV_TIMER_IOCTL_STATUS_COMPAT64 = _IOW('T', 0x14, struct snd_timer_status64),
778c2ecf20Sopenharmony_ci};
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
808c2ecf20Sopenharmony_ci					  unsigned long arg)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	void __user *argp = compat_ptr(arg);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	switch (cmd) {
858c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_PVERSION:
868c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_TREAD_OLD:
878c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_TREAD64:
888c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_GINFO:
898c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_GSTATUS:
908c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_SELECT:
918c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_PARAMS:
928c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_START:
938c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_START_OLD:
948c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_STOP:
958c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_STOP_OLD:
968c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_CONTINUE:
978c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_CONTINUE_OLD:
988c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_PAUSE:
998c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_PAUSE_OLD:
1008c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
1018c2ecf20Sopenharmony_ci		return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp, true);
1028c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_GPARAMS32:
1038c2ecf20Sopenharmony_ci		return snd_timer_user_gparams_compat(file, argp);
1048c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_INFO32:
1058c2ecf20Sopenharmony_ci		return snd_timer_user_info_compat(file, argp);
1068c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_STATUS_COMPAT32:
1078c2ecf20Sopenharmony_ci		return snd_timer_user_status32(file, argp);
1088c2ecf20Sopenharmony_ci	case SNDRV_TIMER_IOCTL_STATUS_COMPAT64:
1098c2ecf20Sopenharmony_ci		return snd_timer_user_status64(file, argp);
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci	return -ENOIOCTLCMD;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
1158c2ecf20Sopenharmony_ci					unsigned long arg)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct snd_timer_user *tu = file->private_data;
1188c2ecf20Sopenharmony_ci	long ret;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	mutex_lock(&tu->ioctl_lock);
1218c2ecf20Sopenharmony_ci	ret = __snd_timer_user_ioctl_compat(file, cmd, arg);
1228c2ecf20Sopenharmony_ci	mutex_unlock(&tu->ioctl_lock);
1238c2ecf20Sopenharmony_ci	return ret;
1248c2ecf20Sopenharmony_ci}
125