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 compat_snd_rawmidi_status64 { 45 s32 stream; 46 u8 rsvd[4]; /* alignment */ 47 s64 tstamp_sec; 48 s64 tstamp_nsec; 49 u32 avail; 50 u32 xruns; 51 unsigned char reserved[16]; 52 } __attribute__((packed)); 53 54 static int snd_rawmidi_ioctl_status_compat64(struct snd_rawmidi_file *rfile, 55 struct compat_snd_rawmidi_status64 __user *src) 56 { 57 int err; 58 struct snd_rawmidi_status64 status; 59 struct compat_snd_rawmidi_status64 compat_status; 60 61 if (get_user(status.stream, &src->stream)) 62 return -EFAULT; 63 64 switch (status.stream) { 65 case SNDRV_RAWMIDI_STREAM_OUTPUT: 66 if (!rfile->output) 67 return -EINVAL; 68 err = snd_rawmidi_output_status(rfile->output, &status); 69 break; 70 case SNDRV_RAWMIDI_STREAM_INPUT: 71 if (!rfile->input) 72 return -EINVAL; 73 err = snd_rawmidi_input_status(rfile->input, &status); 74 break; 75 default: 76 return -EINVAL; 77 } 78 if (err < 0) 79 return err; 80 81 compat_status = (struct compat_snd_rawmidi_status64) { 82 .stream = status.stream, 83 .tstamp_sec = status.tstamp_sec, 84 .tstamp_nsec = status.tstamp_nsec, 85 .avail = status.avail, 86 .xruns = status.xruns, 87 }; 88 89 if (copy_to_user(src, &compat_status, sizeof(*src))) 90 return -EFAULT; 91 92 return 0; 93 } 94 95 enum { 96 SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32), 97 SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT32 = _IOWR('W', 0x20, struct snd_rawmidi_status32), 98 SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT64 = _IOWR('W', 0x20, struct compat_snd_rawmidi_status64), 99 }; 100 101 static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) 102 { 103 struct snd_rawmidi_file *rfile; 104 void __user *argp = compat_ptr(arg); 105 106 rfile = file->private_data; 107 switch (cmd) { 108 case SNDRV_RAWMIDI_IOCTL_PVERSION: 109 case SNDRV_RAWMIDI_IOCTL_INFO: 110 case SNDRV_RAWMIDI_IOCTL_DROP: 111 case SNDRV_RAWMIDI_IOCTL_DRAIN: 112 return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp); 113 case SNDRV_RAWMIDI_IOCTL_PARAMS32: 114 return snd_rawmidi_ioctl_params_compat(rfile, argp); 115 case SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT32: 116 return snd_rawmidi_ioctl_status32(rfile, argp); 117 case SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT64: 118 return snd_rawmidi_ioctl_status_compat64(rfile, argp); 119 } 120 return -ENOIOCTLCMD; 121 } 122