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