1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * 32bit -> 64bit ioctl wrapper for raw MIDI API 4 * Copyright (c) by Takashi Iwai <tiwai@suse.de> 5 */ 6 7 /* This file included from rawmidi.c */ 8 9 #include <linux/compat.h> 10 11 struct snd_rawmidi_params32 { 12 s32 stream; 13 u32 buffer_size; 14 u32 avail_min; 15 unsigned int no_active_sensing; /* avoid bit-field */ 16 unsigned char reserved[16]; 17 } __attribute__((packed)); 18 19 static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, 20 struct snd_rawmidi_params32 __user *src) 21 { 22 struct snd_rawmidi_params params; 23 unsigned int val; 24 25 if (get_user(params.stream, &src->stream) || 26 get_user(params.buffer_size, &src->buffer_size) || 27 get_user(params.avail_min, &src->avail_min) || 28 get_user(val, &src->no_active_sensing)) 29 return -EFAULT; 30 params.no_active_sensing = val; 31 switch (params.stream) { 32 case SNDRV_RAWMIDI_STREAM_OUTPUT: 33 if (!rfile->output) 34 return -EINVAL; 35 return snd_rawmidi_output_params(rfile->output, ¶ms); 36 case SNDRV_RAWMIDI_STREAM_INPUT: 37 if (!rfile->input) 38 return -EINVAL; 39 return snd_rawmidi_input_params(rfile->input, ¶ms); 40 } 41 return -EINVAL; 42 } 43 44 struct snd_rawmidi_status32 { 45 s32 stream; 46 struct compat_timespec tstamp; 47 u32 avail; 48 u32 xruns; 49 unsigned char reserved[16]; 50 } __attribute__((packed)); 51 52 static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile, 53 struct snd_rawmidi_status32 __user *src) 54 { 55 int err; 56 struct snd_rawmidi_status status; 57 58 if (get_user(status.stream, &src->stream)) 59 return -EFAULT; 60 61 switch (status.stream) { 62 case SNDRV_RAWMIDI_STREAM_OUTPUT: 63 if (!rfile->output) 64 return -EINVAL; 65 err = snd_rawmidi_output_status(rfile->output, &status); 66 break; 67 case SNDRV_RAWMIDI_STREAM_INPUT: 68 if (!rfile->input) 69 return -EINVAL; 70 err = snd_rawmidi_input_status(rfile->input, &status); 71 break; 72 default: 73 return -EINVAL; 74 } 75 if (err < 0) 76 return err; 77 78 if (compat_put_timespec(&status.tstamp, &src->tstamp) || 79 put_user(status.avail, &src->avail) || 80 put_user(status.xruns, &src->xruns)) 81 return -EFAULT; 82 83 return 0; 84 } 85 86 #ifdef CONFIG_X86_X32 87 /* X32 ABI has 64bit timespec and 64bit alignment */ 88 struct snd_rawmidi_status_x32 { 89 s32 stream; 90 u32 rsvd; /* alignment */ 91 struct timespec tstamp; 92 u32 avail; 93 u32 xruns; 94 unsigned char reserved[16]; 95 } __attribute__((packed)); 96 97 #define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst)) 98 99 static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile, 100 struct snd_rawmidi_status_x32 __user *src) 101 { 102 int err; 103 struct snd_rawmidi_status status; 104 105 if (get_user(status.stream, &src->stream)) 106 return -EFAULT; 107 108 switch (status.stream) { 109 case SNDRV_RAWMIDI_STREAM_OUTPUT: 110 if (!rfile->output) 111 return -EINVAL; 112 err = snd_rawmidi_output_status(rfile->output, &status); 113 break; 114 case SNDRV_RAWMIDI_STREAM_INPUT: 115 if (!rfile->input) 116 return -EINVAL; 117 err = snd_rawmidi_input_status(rfile->input, &status); 118 break; 119 default: 120 return -EINVAL; 121 } 122 if (err < 0) 123 return err; 124 125 if (put_timespec(&status.tstamp, &src->tstamp) || 126 put_user(status.avail, &src->avail) || 127 put_user(status.xruns, &src->xruns)) 128 return -EFAULT; 129 130 return 0; 131 } 132 #endif /* CONFIG_X86_X32 */ 133 134 enum { 135 SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32), 136 SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32), 137 #ifdef CONFIG_X86_X32 138 SNDRV_RAWMIDI_IOCTL_STATUS_X32 = _IOWR('W', 0x20, struct snd_rawmidi_status_x32), 139 #endif /* CONFIG_X86_X32 */ 140 }; 141 142 static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) 143 { 144 struct snd_rawmidi_file *rfile; 145 void __user *argp = compat_ptr(arg); 146 147 rfile = file->private_data; 148 switch (cmd) { 149 case SNDRV_RAWMIDI_IOCTL_PVERSION: 150 case SNDRV_RAWMIDI_IOCTL_INFO: 151 case SNDRV_RAWMIDI_IOCTL_DROP: 152 case SNDRV_RAWMIDI_IOCTL_DRAIN: 153 return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp); 154 case SNDRV_RAWMIDI_IOCTL_PARAMS32: 155 return snd_rawmidi_ioctl_params_compat(rfile, argp); 156 case SNDRV_RAWMIDI_IOCTL_STATUS32: 157 return snd_rawmidi_ioctl_status_compat(rfile, argp); 158 #ifdef CONFIG_X86_X32 159 case SNDRV_RAWMIDI_IOCTL_STATUS_X32: 160 return snd_rawmidi_ioctl_status_x32(rfile, argp); 161 #endif /* CONFIG_X86_X32 */ 162 } 163 return -ENOIOCTLCMD; 164 } 165