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 53 tu = file->private_data; 54 if (!tu->timeri) 55 return -EBADFD; 56 57 struct snd_timer *t __free(snd_timeri_timer) = 58 snd_timeri_timer_get(tu->timeri); 59 if (!t) 60 return -EBADFD; 61 memset(&info, 0, sizeof(info)); 62 info.card = t->card ? t->card->number : -1; 63 if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) 64 info.flags |= SNDRV_TIMER_FLG_SLAVE; 65 strscpy(info.id, t->id, sizeof(info.id)); 66 strscpy(info.name, t->name, sizeof(info.name)); 67 info.resolution = t->hw.resolution; 68 if (copy_to_user(_info, &info, sizeof(*_info))) 69 return -EFAULT; 70 return 0; 71 } 72 73 enum { 74 SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32), 75 SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), 76 SNDRV_TIMER_IOCTL_STATUS_COMPAT32 = _IOW('T', 0x14, struct snd_timer_status32), 77 SNDRV_TIMER_IOCTL_STATUS_COMPAT64 = _IOW('T', 0x14, struct snd_timer_status64), 78 }; 79 80 static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, 81 unsigned long arg) 82 { 83 void __user *argp = compat_ptr(arg); 84 85 switch (cmd) { 86 case SNDRV_TIMER_IOCTL_PVERSION: 87 case SNDRV_TIMER_IOCTL_TREAD_OLD: 88 case SNDRV_TIMER_IOCTL_TREAD64: 89 case SNDRV_TIMER_IOCTL_GINFO: 90 case SNDRV_TIMER_IOCTL_GSTATUS: 91 case SNDRV_TIMER_IOCTL_SELECT: 92 case SNDRV_TIMER_IOCTL_PARAMS: 93 case SNDRV_TIMER_IOCTL_START: 94 case SNDRV_TIMER_IOCTL_START_OLD: 95 case SNDRV_TIMER_IOCTL_STOP: 96 case SNDRV_TIMER_IOCTL_STOP_OLD: 97 case SNDRV_TIMER_IOCTL_CONTINUE: 98 case SNDRV_TIMER_IOCTL_CONTINUE_OLD: 99 case SNDRV_TIMER_IOCTL_PAUSE: 100 case SNDRV_TIMER_IOCTL_PAUSE_OLD: 101 case SNDRV_TIMER_IOCTL_NEXT_DEVICE: 102 return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp, true); 103 case SNDRV_TIMER_IOCTL_GPARAMS32: 104 return snd_timer_user_gparams_compat(file, argp); 105 case SNDRV_TIMER_IOCTL_INFO32: 106 return snd_timer_user_info_compat(file, argp); 107 case SNDRV_TIMER_IOCTL_STATUS_COMPAT32: 108 return snd_timer_user_status32(file, argp); 109 case SNDRV_TIMER_IOCTL_STATUS_COMPAT64: 110 return snd_timer_user_status64(file, argp); 111 } 112 return -ENOIOCTLCMD; 113 } 114 115 static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, 116 unsigned long arg) 117 { 118 struct snd_timer_user *tu = file->private_data; 119 120 guard(mutex)(&tu->ioctl_lock); 121 return __snd_timer_user_ioctl_compat(file, cmd, arg); 122 } 123