1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * 32bit -> 64bit ioctl wrapper for timer API 4 * Copyright (c) by Takashi Iwai <tiwai@suse.de> 5 */ 6 7 /* This file included from timer.c */ 8 9 #include <linux/compat.h> 10 11 /* 12 * ILP32/LP64 has different size for 'long' type. Additionally, the size 13 * of storage alignment differs depending on architectures. Here, '__packed' 14 * qualifier is used so that the size of this structure is multiple of 4 and 15 * it fits to any architectures with 32 bit storage alignment. 16 */ 17 struct snd_timer_gparams32 { 18 struct snd_timer_id tid; 19 u32 period_num; 20 u32 period_den; 21 unsigned char reserved[32]; 22 } __packed; 23 24 struct snd_timer_info32 { 25 u32 flags; 26 s32 card; 27 unsigned char id[64]; 28 unsigned char name[80]; 29 u32 reserved0; 30 u32 resolution; 31 unsigned char reserved[64]; 32 }; 33 34 static int snd_timer_user_gparams_compat(struct file *file, 35 struct snd_timer_gparams32 __user *user) 36 { 37 struct snd_timer_gparams gparams; 38 39 if (copy_from_user(&gparams.tid, &user->tid, sizeof(gparams.tid)) || 40 get_user(gparams.period_num, &user->period_num) || 41 get_user(gparams.period_den, &user->period_den)) 42 return -EFAULT; 43 44 return timer_set_gparams(&gparams); 45 } 46 47 static int snd_timer_user_info_compat(struct file *file, 48 struct snd_timer_info32 __user *_info) 49 { 50 struct snd_timer_user *tu; 51 struct snd_timer_info32 info; 52 struct snd_timer *t; 53 54 tu = file->private_data; 55 if (!tu->timeri) 56 return -EBADFD; 57 t = tu->timeri->timer; 58 if (!t) 59 return -EBADFD; 60 memset(&info, 0, sizeof(info)); 61 info.card = t->card ? t->card->number : -1; 62 if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) 63 info.flags |= SNDRV_TIMER_FLG_SLAVE; 64 strlcpy(info.id, t->id, sizeof(info.id)); 65 strlcpy(info.name, t->name, sizeof(info.name)); 66 info.resolution = t->hw.resolution; 67 if (copy_to_user(_info, &info, sizeof(*_info))) 68 return -EFAULT; 69 return 0; 70 } 71 72 enum { 73 SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32), 74 SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), 75 SNDRV_TIMER_IOCTL_STATUS_COMPAT32 = _IOW('T', 0x14, struct snd_timer_status32), 76 SNDRV_TIMER_IOCTL_STATUS_COMPAT64 = _IOW('T', 0x14, struct snd_timer_status64), 77 }; 78 79 static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, 80 unsigned long arg) 81 { 82 void __user *argp = compat_ptr(arg); 83 84 switch (cmd) { 85 case SNDRV_TIMER_IOCTL_PVERSION: 86 case SNDRV_TIMER_IOCTL_TREAD_OLD: 87 case SNDRV_TIMER_IOCTL_TREAD64: 88 case SNDRV_TIMER_IOCTL_GINFO: 89 case SNDRV_TIMER_IOCTL_GSTATUS: 90 case SNDRV_TIMER_IOCTL_SELECT: 91 case SNDRV_TIMER_IOCTL_PARAMS: 92 case SNDRV_TIMER_IOCTL_START: 93 case SNDRV_TIMER_IOCTL_START_OLD: 94 case SNDRV_TIMER_IOCTL_STOP: 95 case SNDRV_TIMER_IOCTL_STOP_OLD: 96 case SNDRV_TIMER_IOCTL_CONTINUE: 97 case SNDRV_TIMER_IOCTL_CONTINUE_OLD: 98 case SNDRV_TIMER_IOCTL_PAUSE: 99 case SNDRV_TIMER_IOCTL_PAUSE_OLD: 100 case SNDRV_TIMER_IOCTL_NEXT_DEVICE: 101 return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp, true); 102 case SNDRV_TIMER_IOCTL_GPARAMS32: 103 return snd_timer_user_gparams_compat(file, argp); 104 case SNDRV_TIMER_IOCTL_INFO32: 105 return snd_timer_user_info_compat(file, argp); 106 case SNDRV_TIMER_IOCTL_STATUS_COMPAT32: 107 return snd_timer_user_status32(file, argp); 108 case SNDRV_TIMER_IOCTL_STATUS_COMPAT64: 109 return snd_timer_user_status64(file, argp); 110 } 111 return -ENOIOCTLCMD; 112 } 113 114 static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, 115 unsigned long arg) 116 { 117 struct snd_timer_user *tu = file->private_data; 118 long ret; 119 120 mutex_lock(&tu->ioctl_lock); 121 ret = __snd_timer_user_ioctl_compat(file, cmd, arg); 122 mutex_unlock(&tu->ioctl_lock); 123 return ret; 124 } 125