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 int mode; 17 unsigned char reserved[12]; 18 } __attribute__((packed)); 19 20 static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, 21 struct snd_rawmidi_params32 __user *src) 22 { 23 struct snd_rawmidi_params params; 24 unsigned int val; 25 26 if (get_user(params.stream, &src->stream) || 27 get_user(params.buffer_size, &src->buffer_size) || 28 get_user(params.avail_min, &src->avail_min) || 29 get_user(params.mode, &src->mode) || 30 get_user(val, &src->no_active_sensing)) 31 return -EFAULT; 32 params.no_active_sensing = val; 33 switch (params.stream) { 34 case SNDRV_RAWMIDI_STREAM_OUTPUT: 35 if (!rfile->output) 36 return -EINVAL; 37 return snd_rawmidi_output_params(rfile->output, ¶ms); 38 case SNDRV_RAWMIDI_STREAM_INPUT: 39 if (!rfile->input) 40 return -EINVAL; 41 return snd_rawmidi_input_params(rfile->input, ¶ms); 42 } 43 return -EINVAL; 44 } 45 46 struct compat_snd_rawmidi_status64 { 47 s32 stream; 48 u8 rsvd[4]; /* alignment */ 49 s64 tstamp_sec; 50 s64 tstamp_nsec; 51 u32 avail; 52 u32 xruns; 53 unsigned char reserved[16]; 54 } __attribute__((packed)); 55 56 static int snd_rawmidi_ioctl_status_compat64(struct snd_rawmidi_file *rfile, 57 struct compat_snd_rawmidi_status64 __user *src) 58 { 59 int err; 60 struct snd_rawmidi_status64 status; 61 struct compat_snd_rawmidi_status64 compat_status; 62 63 if (get_user(status.stream, &src->stream)) 64 return -EFAULT; 65 66 switch (status.stream) { 67 case SNDRV_RAWMIDI_STREAM_OUTPUT: 68 if (!rfile->output) 69 return -EINVAL; 70 err = snd_rawmidi_output_status(rfile->output, &status); 71 break; 72 case SNDRV_RAWMIDI_STREAM_INPUT: 73 if (!rfile->input) 74 return -EINVAL; 75 err = snd_rawmidi_input_status(rfile->input, &status); 76 break; 77 default: 78 return -EINVAL; 79 } 80 if (err < 0) 81 return err; 82 83 compat_status = (struct compat_snd_rawmidi_status64) { 84 .stream = status.stream, 85 .tstamp_sec = status.tstamp_sec, 86 .tstamp_nsec = status.tstamp_nsec, 87 .avail = status.avail, 88 .xruns = status.xruns, 89 }; 90 91 if (copy_to_user(src, &compat_status, sizeof(*src))) 92 return -EFAULT; 93 94 return 0; 95 } 96 97 enum { 98 SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32), 99 SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT32 = _IOWR('W', 0x20, struct snd_rawmidi_status32), 100 SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT64 = _IOWR('W', 0x20, struct compat_snd_rawmidi_status64), 101 }; 102 103 static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) 104 { 105 struct snd_rawmidi_file *rfile; 106 void __user *argp = compat_ptr(arg); 107 108 rfile = file->private_data; 109 switch (cmd) { 110 case SNDRV_RAWMIDI_IOCTL_PVERSION: 111 case SNDRV_RAWMIDI_IOCTL_INFO: 112 case SNDRV_RAWMIDI_IOCTL_DROP: 113 case SNDRV_RAWMIDI_IOCTL_DRAIN: 114 #if IS_ENABLED(CONFIG_SND_UMP) 115 case SNDRV_UMP_IOCTL_ENDPOINT_INFO: 116 case SNDRV_UMP_IOCTL_BLOCK_INFO: 117 #endif 118 return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp); 119 case SNDRV_RAWMIDI_IOCTL_PARAMS32: 120 return snd_rawmidi_ioctl_params_compat(rfile, argp); 121 case SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT32: 122 return snd_rawmidi_ioctl_status32(rfile, argp); 123 case SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT64: 124 return snd_rawmidi_ioctl_status_compat64(rfile, argp); 125 } 126 return -ENOIOCTLCMD; 127 } 128