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 
snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file * rfile,struct snd_rawmidi_params32 __user * src)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, &params);
38 	case SNDRV_RAWMIDI_STREAM_INPUT:
39 		if (!rfile->input)
40 			return -EINVAL;
41 		return snd_rawmidi_input_params(rfile->input, &params);
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 
snd_rawmidi_ioctl_status_compat64(struct snd_rawmidi_file * rfile,struct compat_snd_rawmidi_status64 __user * src)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 
snd_rawmidi_ioctl_compat(struct file * file,unsigned int cmd,unsigned long arg)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 		return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
115 	case SNDRV_RAWMIDI_IOCTL_PARAMS32:
116 		return snd_rawmidi_ioctl_params_compat(rfile, argp);
117 	case SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT32:
118 		return snd_rawmidi_ioctl_status32(rfile, argp);
119 	case SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT64:
120 		return snd_rawmidi_ioctl_status_compat64(rfile, argp);
121 	}
122 	return -ENOIOCTLCMD;
123 }
124