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 struct snd_timer_status32 { 73 struct compat_timespec tstamp; 74 u32 resolution; 75 u32 lost; 76 u32 overrun; 77 u32 queue; 78 unsigned char reserved[64]; 79 }; 80 81 static int snd_timer_user_status_compat(struct file *file, 82 struct snd_timer_status32 __user *_status) 83 { 84 struct snd_timer_user *tu; 85 struct snd_timer_status32 status; 86 87 tu = file->private_data; 88 if (!tu->timeri) 89 return -EBADFD; 90 memset(&status, 0, sizeof(status)); 91 status.tstamp.tv_sec = tu->tstamp.tv_sec; 92 status.tstamp.tv_nsec = tu->tstamp.tv_nsec; 93 status.resolution = snd_timer_resolution(tu->timeri); 94 status.lost = tu->timeri->lost; 95 status.overrun = tu->overrun; 96 spin_lock_irq(&tu->qlock); 97 status.queue = tu->qused; 98 spin_unlock_irq(&tu->qlock); 99 if (copy_to_user(_status, &status, sizeof(status))) 100 return -EFAULT; 101 return 0; 102 } 103 104 #ifdef CONFIG_X86_X32 105 /* X32 ABI has the same struct as x86-64 */ 106 #define snd_timer_user_status_x32(file, s) \ 107 snd_timer_user_status(file, s) 108 #endif /* CONFIG_X86_X32 */ 109 110 /* 111 */ 112 113 enum { 114 SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32), 115 SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), 116 SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32), 117 #ifdef CONFIG_X86_X32 118 SNDRV_TIMER_IOCTL_STATUS_X32 = _IOW('T', 0x14, struct snd_timer_status), 119 #endif /* CONFIG_X86_X32 */ 120 }; 121 122 static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, 123 unsigned long arg) 124 { 125 void __user *argp = compat_ptr(arg); 126 127 switch (cmd) { 128 case SNDRV_TIMER_IOCTL_PVERSION: 129 case SNDRV_TIMER_IOCTL_TREAD: 130 case SNDRV_TIMER_IOCTL_GINFO: 131 case SNDRV_TIMER_IOCTL_GSTATUS: 132 case SNDRV_TIMER_IOCTL_SELECT: 133 case SNDRV_TIMER_IOCTL_PARAMS: 134 case SNDRV_TIMER_IOCTL_START: 135 case SNDRV_TIMER_IOCTL_START_OLD: 136 case SNDRV_TIMER_IOCTL_STOP: 137 case SNDRV_TIMER_IOCTL_STOP_OLD: 138 case SNDRV_TIMER_IOCTL_CONTINUE: 139 case SNDRV_TIMER_IOCTL_CONTINUE_OLD: 140 case SNDRV_TIMER_IOCTL_PAUSE: 141 case SNDRV_TIMER_IOCTL_PAUSE_OLD: 142 case SNDRV_TIMER_IOCTL_NEXT_DEVICE: 143 return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp); 144 case SNDRV_TIMER_IOCTL_GPARAMS32: 145 return snd_timer_user_gparams_compat(file, argp); 146 case SNDRV_TIMER_IOCTL_INFO32: 147 return snd_timer_user_info_compat(file, argp); 148 case SNDRV_TIMER_IOCTL_STATUS32: 149 return snd_timer_user_status_compat(file, argp); 150 #ifdef CONFIG_X86_X32 151 case SNDRV_TIMER_IOCTL_STATUS_X32: 152 return snd_timer_user_status_x32(file, argp); 153 #endif /* CONFIG_X86_X32 */ 154 } 155 return -ENOIOCTLCMD; 156 } 157 158 static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, 159 unsigned long arg) 160 { 161 struct snd_timer_user *tu = file->private_data; 162 long ret; 163 164 mutex_lock(&tu->ioctl_lock); 165 ret = __snd_timer_user_ioctl_compat(file, cmd, arg); 166 mutex_unlock(&tu->ioctl_lock); 167 return ret; 168 } 169