xref: /openbmc/linux/sound/core/rawmidi_compat.c (revision 1a59d1b8)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *   32bit -> 64bit ioctl wrapper for raw MIDI API
41da177e4SLinus Torvalds  *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds /* This file included from rawmidi.c */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #include <linux/compat.h>
101da177e4SLinus Torvalds 
1148c9d417STakashi Iwai struct snd_rawmidi_params32 {
121da177e4SLinus Torvalds 	s32 stream;
131da177e4SLinus Torvalds 	u32 buffer_size;
141da177e4SLinus Torvalds 	u32 avail_min;
151da177e4SLinus Torvalds 	unsigned int no_active_sensing; /* avoid bit-field */
161da177e4SLinus Torvalds 	unsigned char reserved[16];
171da177e4SLinus Torvalds } __attribute__((packed));
181da177e4SLinus Torvalds 
1948c9d417STakashi Iwai static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile,
2048c9d417STakashi Iwai 					   struct snd_rawmidi_params32 __user *src)
211da177e4SLinus Torvalds {
2248c9d417STakashi Iwai 	struct snd_rawmidi_params params;
231da177e4SLinus Torvalds 	unsigned int val;
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds 	if (get_user(params.stream, &src->stream) ||
261da177e4SLinus Torvalds 	    get_user(params.buffer_size, &src->buffer_size) ||
271da177e4SLinus Torvalds 	    get_user(params.avail_min, &src->avail_min) ||
281da177e4SLinus Torvalds 	    get_user(val, &src->no_active_sensing))
291da177e4SLinus Torvalds 		return -EFAULT;
301da177e4SLinus Torvalds 	params.no_active_sensing = val;
311da177e4SLinus Torvalds 	switch (params.stream) {
321da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_STREAM_OUTPUT:
338a56ef4fSTakashi Iwai 		if (!rfile->output)
348a56ef4fSTakashi Iwai 			return -EINVAL;
351da177e4SLinus Torvalds 		return snd_rawmidi_output_params(rfile->output, &params);
361da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_STREAM_INPUT:
378a56ef4fSTakashi Iwai 		if (!rfile->input)
388a56ef4fSTakashi Iwai 			return -EINVAL;
391da177e4SLinus Torvalds 		return snd_rawmidi_input_params(rfile->input, &params);
401da177e4SLinus Torvalds 	}
411da177e4SLinus Torvalds 	return -EINVAL;
421da177e4SLinus Torvalds }
431da177e4SLinus Torvalds 
4448c9d417STakashi Iwai struct snd_rawmidi_status32 {
451da177e4SLinus Torvalds 	s32 stream;
461da177e4SLinus Torvalds 	struct compat_timespec tstamp;
471da177e4SLinus Torvalds 	u32 avail;
481da177e4SLinus Torvalds 	u32 xruns;
491da177e4SLinus Torvalds 	unsigned char reserved[16];
501da177e4SLinus Torvalds } __attribute__((packed));
511da177e4SLinus Torvalds 
5248c9d417STakashi Iwai static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile,
5348c9d417STakashi Iwai 					   struct snd_rawmidi_status32 __user *src)
541da177e4SLinus Torvalds {
551da177e4SLinus Torvalds 	int err;
5648c9d417STakashi Iwai 	struct snd_rawmidi_status status;
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 	if (get_user(status.stream, &src->stream))
591da177e4SLinus Torvalds 		return -EFAULT;
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 	switch (status.stream) {
621da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_STREAM_OUTPUT:
638a56ef4fSTakashi Iwai 		if (!rfile->output)
648a56ef4fSTakashi Iwai 			return -EINVAL;
651da177e4SLinus Torvalds 		err = snd_rawmidi_output_status(rfile->output, &status);
661da177e4SLinus Torvalds 		break;
671da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_STREAM_INPUT:
688a56ef4fSTakashi Iwai 		if (!rfile->input)
698a56ef4fSTakashi Iwai 			return -EINVAL;
701da177e4SLinus Torvalds 		err = snd_rawmidi_input_status(rfile->input, &status);
711da177e4SLinus Torvalds 		break;
721da177e4SLinus Torvalds 	default:
731da177e4SLinus Torvalds 		return -EINVAL;
741da177e4SLinus Torvalds 	}
751da177e4SLinus Torvalds 	if (err < 0)
761da177e4SLinus Torvalds 		return err;
771da177e4SLinus Torvalds 
78dd7e3f80STakashi Iwai 	if (compat_put_timespec(&status.tstamp, &src->tstamp) ||
791da177e4SLinus Torvalds 	    put_user(status.avail, &src->avail) ||
801da177e4SLinus Torvalds 	    put_user(status.xruns, &src->xruns))
811da177e4SLinus Torvalds 		return -EFAULT;
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds 	return 0;
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds 
862251fbbcSTakashi Iwai #ifdef CONFIG_X86_X32
872251fbbcSTakashi Iwai /* X32 ABI has 64bit timespec and 64bit alignment */
882251fbbcSTakashi Iwai struct snd_rawmidi_status_x32 {
892251fbbcSTakashi Iwai 	s32 stream;
902251fbbcSTakashi Iwai 	u32 rsvd; /* alignment */
912251fbbcSTakashi Iwai 	struct timespec tstamp;
922251fbbcSTakashi Iwai 	u32 avail;
932251fbbcSTakashi Iwai 	u32 xruns;
942251fbbcSTakashi Iwai 	unsigned char reserved[16];
952251fbbcSTakashi Iwai } __attribute__((packed));
962251fbbcSTakashi Iwai 
972251fbbcSTakashi Iwai #define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
982251fbbcSTakashi Iwai 
992251fbbcSTakashi Iwai static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile,
1002251fbbcSTakashi Iwai 					struct snd_rawmidi_status_x32 __user *src)
1012251fbbcSTakashi Iwai {
1022251fbbcSTakashi Iwai 	int err;
1032251fbbcSTakashi Iwai 	struct snd_rawmidi_status status;
1042251fbbcSTakashi Iwai 
1052251fbbcSTakashi Iwai 	if (get_user(status.stream, &src->stream))
1062251fbbcSTakashi Iwai 		return -EFAULT;
1072251fbbcSTakashi Iwai 
1082251fbbcSTakashi Iwai 	switch (status.stream) {
1092251fbbcSTakashi Iwai 	case SNDRV_RAWMIDI_STREAM_OUTPUT:
1108a56ef4fSTakashi Iwai 		if (!rfile->output)
1118a56ef4fSTakashi Iwai 			return -EINVAL;
1122251fbbcSTakashi Iwai 		err = snd_rawmidi_output_status(rfile->output, &status);
1132251fbbcSTakashi Iwai 		break;
1142251fbbcSTakashi Iwai 	case SNDRV_RAWMIDI_STREAM_INPUT:
1158a56ef4fSTakashi Iwai 		if (!rfile->input)
1168a56ef4fSTakashi Iwai 			return -EINVAL;
1172251fbbcSTakashi Iwai 		err = snd_rawmidi_input_status(rfile->input, &status);
1182251fbbcSTakashi Iwai 		break;
1192251fbbcSTakashi Iwai 	default:
1202251fbbcSTakashi Iwai 		return -EINVAL;
1212251fbbcSTakashi Iwai 	}
1222251fbbcSTakashi Iwai 	if (err < 0)
1232251fbbcSTakashi Iwai 		return err;
1242251fbbcSTakashi Iwai 
1252251fbbcSTakashi Iwai 	if (put_timespec(&status.tstamp, &src->tstamp) ||
1262251fbbcSTakashi Iwai 	    put_user(status.avail, &src->avail) ||
1272251fbbcSTakashi Iwai 	    put_user(status.xruns, &src->xruns))
1282251fbbcSTakashi Iwai 		return -EFAULT;
1292251fbbcSTakashi Iwai 
1302251fbbcSTakashi Iwai 	return 0;
1312251fbbcSTakashi Iwai }
1322251fbbcSTakashi Iwai #endif /* CONFIG_X86_X32 */
1332251fbbcSTakashi Iwai 
1341da177e4SLinus Torvalds enum {
13548c9d417STakashi Iwai 	SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32),
13648c9d417STakashi Iwai 	SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32),
1372251fbbcSTakashi Iwai #ifdef CONFIG_X86_X32
1382251fbbcSTakashi Iwai 	SNDRV_RAWMIDI_IOCTL_STATUS_X32 = _IOWR('W', 0x20, struct snd_rawmidi_status_x32),
1392251fbbcSTakashi Iwai #endif /* CONFIG_X86_X32 */
1401da177e4SLinus Torvalds };
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
1431da177e4SLinus Torvalds {
14448c9d417STakashi Iwai 	struct snd_rawmidi_file *rfile;
1451da177e4SLinus Torvalds 	void __user *argp = compat_ptr(arg);
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 	rfile = file->private_data;
1481da177e4SLinus Torvalds 	switch (cmd) {
1491da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_PVERSION:
1501da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_INFO:
1511da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_DROP:
1521da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_DRAIN:
1531da177e4SLinus Torvalds 		return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
1541da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_PARAMS32:
1551da177e4SLinus Torvalds 		return snd_rawmidi_ioctl_params_compat(rfile, argp);
1561da177e4SLinus Torvalds 	case SNDRV_RAWMIDI_IOCTL_STATUS32:
1571da177e4SLinus Torvalds 		return snd_rawmidi_ioctl_status_compat(rfile, argp);
1582251fbbcSTakashi Iwai #ifdef CONFIG_X86_X32
1592251fbbcSTakashi Iwai 	case SNDRV_RAWMIDI_IOCTL_STATUS_X32:
1602251fbbcSTakashi Iwai 		return snd_rawmidi_ioctl_status_x32(rfile, argp);
1612251fbbcSTakashi Iwai #endif /* CONFIG_X86_X32 */
1621da177e4SLinus Torvalds 	}
1631da177e4SLinus Torvalds 	return -ENOIOCTLCMD;
1641da177e4SLinus Torvalds }
165