xref: /openbmc/linux/sound/core/rawmidi_compat.c (revision 8a56ef4f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *   32bit -> 64bit ioctl wrapper for raw MIDI API
31da177e4SLinus Torvalds  *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *   This program is free software; you can redistribute it and/or modify
61da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
71da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
81da177e4SLinus Torvalds  *   (at your option) any later version.
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
111da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
121da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
131da177e4SLinus Torvalds  *   GNU General Public License for more details.
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
161da177e4SLinus Torvalds  *   along with this program; if not, write to the Free Software
171da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
181da177e4SLinus Torvalds  *
191da177e4SLinus Torvalds  */
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds /* This file included from rawmidi.c */
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #include <linux/compat.h>
241da177e4SLinus Torvalds 
2548c9d417STakashi Iwai struct snd_rawmidi_params32 {
261da177e4SLinus Torvalds 	s32 stream;
271da177e4SLinus Torvalds 	u32 buffer_size;
281da177e4SLinus Torvalds 	u32 avail_min;
291da177e4SLinus Torvalds 	unsigned int no_active_sensing; /* avoid bit-field */
301da177e4SLinus Torvalds 	unsigned char reserved[16];
311da177e4SLinus Torvalds } __attribute__((packed));
321da177e4SLinus Torvalds 
3348c9d417STakashi Iwai static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile,
3448c9d417STakashi Iwai 					   struct snd_rawmidi_params32 __user *src)
351da177e4SLinus Torvalds {
3648c9d417STakashi Iwai 	struct snd_rawmidi_params params;
371da177e4SLinus Torvalds 	unsigned int val;
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds 	if (get_user(params.stream, &src->stream) ||
401da177e4SLinus Torvalds 	    get_user(params.buffer_size, &src->buffer_size) ||
411da177e4SLinus Torvalds 	    get_user(params.avail_min, &src->avail_min) ||
421da177e4SLinus Torvalds 	    get_user(val, &src->no_active_sensing))
431da177e4SLinus Torvalds 		return -EFAULT;
441da177e4SLinus Torvalds 	params.no_active_sensing = val;
451da177e4SLinus Torvalds 	switch (params.stream) {
461da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_STREAM_OUTPUT:
478a56ef4fSTakashi Iwai 		if (!rfile->output)
488a56ef4fSTakashi Iwai 			return -EINVAL;
491da177e4SLinus Torvalds 		return snd_rawmidi_output_params(rfile->output, &params);
501da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_STREAM_INPUT:
518a56ef4fSTakashi Iwai 		if (!rfile->input)
528a56ef4fSTakashi Iwai 			return -EINVAL;
531da177e4SLinus Torvalds 		return snd_rawmidi_input_params(rfile->input, &params);
541da177e4SLinus Torvalds 	}
551da177e4SLinus Torvalds 	return -EINVAL;
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds 
5848c9d417STakashi Iwai struct snd_rawmidi_status32 {
591da177e4SLinus Torvalds 	s32 stream;
601da177e4SLinus Torvalds 	struct compat_timespec tstamp;
611da177e4SLinus Torvalds 	u32 avail;
621da177e4SLinus Torvalds 	u32 xruns;
631da177e4SLinus Torvalds 	unsigned char reserved[16];
641da177e4SLinus Torvalds } __attribute__((packed));
651da177e4SLinus Torvalds 
6648c9d417STakashi Iwai static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile,
6748c9d417STakashi Iwai 					   struct snd_rawmidi_status32 __user *src)
681da177e4SLinus Torvalds {
691da177e4SLinus Torvalds 	int err;
7048c9d417STakashi Iwai 	struct snd_rawmidi_status status;
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 	if (get_user(status.stream, &src->stream))
731da177e4SLinus Torvalds 		return -EFAULT;
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds 	switch (status.stream) {
761da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_STREAM_OUTPUT:
778a56ef4fSTakashi Iwai 		if (!rfile->output)
788a56ef4fSTakashi Iwai 			return -EINVAL;
791da177e4SLinus Torvalds 		err = snd_rawmidi_output_status(rfile->output, &status);
801da177e4SLinus Torvalds 		break;
811da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_STREAM_INPUT:
828a56ef4fSTakashi Iwai 		if (!rfile->input)
838a56ef4fSTakashi Iwai 			return -EINVAL;
841da177e4SLinus Torvalds 		err = snd_rawmidi_input_status(rfile->input, &status);
851da177e4SLinus Torvalds 		break;
861da177e4SLinus Torvalds 	default:
871da177e4SLinus Torvalds 		return -EINVAL;
881da177e4SLinus Torvalds 	}
891da177e4SLinus Torvalds 	if (err < 0)
901da177e4SLinus Torvalds 		return err;
911da177e4SLinus Torvalds 
92dd7e3f80STakashi Iwai 	if (compat_put_timespec(&status.tstamp, &src->tstamp) ||
931da177e4SLinus Torvalds 	    put_user(status.avail, &src->avail) ||
941da177e4SLinus Torvalds 	    put_user(status.xruns, &src->xruns))
951da177e4SLinus Torvalds 		return -EFAULT;
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	return 0;
981da177e4SLinus Torvalds }
991da177e4SLinus Torvalds 
1002251fbbcSTakashi Iwai #ifdef CONFIG_X86_X32
1012251fbbcSTakashi Iwai /* X32 ABI has 64bit timespec and 64bit alignment */
1022251fbbcSTakashi Iwai struct snd_rawmidi_status_x32 {
1032251fbbcSTakashi Iwai 	s32 stream;
1042251fbbcSTakashi Iwai 	u32 rsvd; /* alignment */
1052251fbbcSTakashi Iwai 	struct timespec tstamp;
1062251fbbcSTakashi Iwai 	u32 avail;
1072251fbbcSTakashi Iwai 	u32 xruns;
1082251fbbcSTakashi Iwai 	unsigned char reserved[16];
1092251fbbcSTakashi Iwai } __attribute__((packed));
1102251fbbcSTakashi Iwai 
1112251fbbcSTakashi Iwai #define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
1122251fbbcSTakashi Iwai 
1132251fbbcSTakashi Iwai static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile,
1142251fbbcSTakashi Iwai 					struct snd_rawmidi_status_x32 __user *src)
1152251fbbcSTakashi Iwai {
1162251fbbcSTakashi Iwai 	int err;
1172251fbbcSTakashi Iwai 	struct snd_rawmidi_status status;
1182251fbbcSTakashi Iwai 
1192251fbbcSTakashi Iwai 	if (get_user(status.stream, &src->stream))
1202251fbbcSTakashi Iwai 		return -EFAULT;
1212251fbbcSTakashi Iwai 
1222251fbbcSTakashi Iwai 	switch (status.stream) {
1232251fbbcSTakashi Iwai 	case SNDRV_RAWMIDI_STREAM_OUTPUT:
1248a56ef4fSTakashi Iwai 		if (!rfile->output)
1258a56ef4fSTakashi Iwai 			return -EINVAL;
1262251fbbcSTakashi Iwai 		err = snd_rawmidi_output_status(rfile->output, &status);
1272251fbbcSTakashi Iwai 		break;
1282251fbbcSTakashi Iwai 	case SNDRV_RAWMIDI_STREAM_INPUT:
1298a56ef4fSTakashi Iwai 		if (!rfile->input)
1308a56ef4fSTakashi Iwai 			return -EINVAL;
1312251fbbcSTakashi Iwai 		err = snd_rawmidi_input_status(rfile->input, &status);
1322251fbbcSTakashi Iwai 		break;
1332251fbbcSTakashi Iwai 	default:
1342251fbbcSTakashi Iwai 		return -EINVAL;
1352251fbbcSTakashi Iwai 	}
1362251fbbcSTakashi Iwai 	if (err < 0)
1372251fbbcSTakashi Iwai 		return err;
1382251fbbcSTakashi Iwai 
1392251fbbcSTakashi Iwai 	if (put_timespec(&status.tstamp, &src->tstamp) ||
1402251fbbcSTakashi Iwai 	    put_user(status.avail, &src->avail) ||
1412251fbbcSTakashi Iwai 	    put_user(status.xruns, &src->xruns))
1422251fbbcSTakashi Iwai 		return -EFAULT;
1432251fbbcSTakashi Iwai 
1442251fbbcSTakashi Iwai 	return 0;
1452251fbbcSTakashi Iwai }
1462251fbbcSTakashi Iwai #endif /* CONFIG_X86_X32 */
1472251fbbcSTakashi Iwai 
1481da177e4SLinus Torvalds enum {
14948c9d417STakashi Iwai 	SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32),
15048c9d417STakashi Iwai 	SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32),
1512251fbbcSTakashi Iwai #ifdef CONFIG_X86_X32
1522251fbbcSTakashi Iwai 	SNDRV_RAWMIDI_IOCTL_STATUS_X32 = _IOWR('W', 0x20, struct snd_rawmidi_status_x32),
1532251fbbcSTakashi Iwai #endif /* CONFIG_X86_X32 */
1541da177e4SLinus Torvalds };
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
1571da177e4SLinus Torvalds {
15848c9d417STakashi Iwai 	struct snd_rawmidi_file *rfile;
1591da177e4SLinus Torvalds 	void __user *argp = compat_ptr(arg);
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 	rfile = file->private_data;
1621da177e4SLinus Torvalds 	switch (cmd) {
1631da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_PVERSION:
1641da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_INFO:
1651da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_DROP:
1661da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_DRAIN:
1671da177e4SLinus Torvalds 		return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
1681da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_PARAMS32:
1691da177e4SLinus Torvalds 		return snd_rawmidi_ioctl_params_compat(rfile, argp);
1701da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_STATUS32:
1711da177e4SLinus Torvalds 		return snd_rawmidi_ioctl_status_compat(rfile, argp);
1722251fbbcSTakashi Iwai #ifdef CONFIG_X86_X32
1732251fbbcSTakashi Iwai 	case SNDRV_RAWMIDI_IOCTL_STATUS_X32:
1742251fbbcSTakashi Iwai 		return snd_rawmidi_ioctl_status_x32(rfile, argp);
1752251fbbcSTakashi Iwai #endif /* CONFIG_X86_X32 */
1761da177e4SLinus Torvalds 	}
1771da177e4SLinus Torvalds 	return -ENOIOCTLCMD;
1781da177e4SLinus Torvalds }
179