xref: /OK3568_Linux_fs/kernel/sound/core/timer_compat.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *   32bit -> 64bit ioctl wrapper for timer API
4*4882a593Smuzhiyun  *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun /* This file included from timer.c */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/compat.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun /*
12*4882a593Smuzhiyun  * ILP32/LP64 has different size for 'long' type. Additionally, the size
13*4882a593Smuzhiyun  * of storage alignment differs depending on architectures. Here, '__packed'
14*4882a593Smuzhiyun  * qualifier is used so that the size of this structure is multiple of 4 and
15*4882a593Smuzhiyun  * it fits to any architectures with 32 bit storage alignment.
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun struct snd_timer_gparams32 {
18*4882a593Smuzhiyun 	struct snd_timer_id tid;
19*4882a593Smuzhiyun 	u32 period_num;
20*4882a593Smuzhiyun 	u32 period_den;
21*4882a593Smuzhiyun 	unsigned char reserved[32];
22*4882a593Smuzhiyun } __packed;
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun struct snd_timer_info32 {
25*4882a593Smuzhiyun 	u32 flags;
26*4882a593Smuzhiyun 	s32 card;
27*4882a593Smuzhiyun 	unsigned char id[64];
28*4882a593Smuzhiyun 	unsigned char name[80];
29*4882a593Smuzhiyun 	u32 reserved0;
30*4882a593Smuzhiyun 	u32 resolution;
31*4882a593Smuzhiyun 	unsigned char reserved[64];
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun 
snd_timer_user_gparams_compat(struct file * file,struct snd_timer_gparams32 __user * user)34*4882a593Smuzhiyun static int snd_timer_user_gparams_compat(struct file *file,
35*4882a593Smuzhiyun 					struct snd_timer_gparams32 __user *user)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	struct snd_timer_gparams gparams;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	if (copy_from_user(&gparams.tid, &user->tid, sizeof(gparams.tid)) ||
40*4882a593Smuzhiyun 	    get_user(gparams.period_num, &user->period_num) ||
41*4882a593Smuzhiyun 	    get_user(gparams.period_den, &user->period_den))
42*4882a593Smuzhiyun 		return -EFAULT;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	return timer_set_gparams(&gparams);
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun 
snd_timer_user_info_compat(struct file * file,struct snd_timer_info32 __user * _info)47*4882a593Smuzhiyun static int snd_timer_user_info_compat(struct file *file,
48*4882a593Smuzhiyun 				      struct snd_timer_info32 __user *_info)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	struct snd_timer_user *tu;
51*4882a593Smuzhiyun 	struct snd_timer_info32 info;
52*4882a593Smuzhiyun 	struct snd_timer *t;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	tu = file->private_data;
55*4882a593Smuzhiyun 	if (!tu->timeri)
56*4882a593Smuzhiyun 		return -EBADFD;
57*4882a593Smuzhiyun 	t = tu->timeri->timer;
58*4882a593Smuzhiyun 	if (!t)
59*4882a593Smuzhiyun 		return -EBADFD;
60*4882a593Smuzhiyun 	memset(&info, 0, sizeof(info));
61*4882a593Smuzhiyun 	info.card = t->card ? t->card->number : -1;
62*4882a593Smuzhiyun 	if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
63*4882a593Smuzhiyun 		info.flags |= SNDRV_TIMER_FLG_SLAVE;
64*4882a593Smuzhiyun 	strlcpy(info.id, t->id, sizeof(info.id));
65*4882a593Smuzhiyun 	strlcpy(info.name, t->name, sizeof(info.name));
66*4882a593Smuzhiyun 	info.resolution = t->hw.resolution;
67*4882a593Smuzhiyun 	if (copy_to_user(_info, &info, sizeof(*_info)))
68*4882a593Smuzhiyun 		return -EFAULT;
69*4882a593Smuzhiyun 	return 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun enum {
73*4882a593Smuzhiyun 	SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32),
74*4882a593Smuzhiyun 	SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32),
75*4882a593Smuzhiyun 	SNDRV_TIMER_IOCTL_STATUS_COMPAT32 = _IOW('T', 0x14, struct snd_timer_status32),
76*4882a593Smuzhiyun 	SNDRV_TIMER_IOCTL_STATUS_COMPAT64 = _IOW('T', 0x14, struct snd_timer_status64),
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun 
__snd_timer_user_ioctl_compat(struct file * file,unsigned int cmd,unsigned long arg)79*4882a593Smuzhiyun static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
80*4882a593Smuzhiyun 					  unsigned long arg)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	void __user *argp = compat_ptr(arg);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	switch (cmd) {
85*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_PVERSION:
86*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_TREAD_OLD:
87*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_TREAD64:
88*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_GINFO:
89*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_GSTATUS:
90*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_SELECT:
91*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_PARAMS:
92*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_START:
93*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_START_OLD:
94*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_STOP:
95*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_STOP_OLD:
96*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_CONTINUE:
97*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_CONTINUE_OLD:
98*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_PAUSE:
99*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_PAUSE_OLD:
100*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
101*4882a593Smuzhiyun 		return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp, true);
102*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_GPARAMS32:
103*4882a593Smuzhiyun 		return snd_timer_user_gparams_compat(file, argp);
104*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_INFO32:
105*4882a593Smuzhiyun 		return snd_timer_user_info_compat(file, argp);
106*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_STATUS_COMPAT32:
107*4882a593Smuzhiyun 		return snd_timer_user_status32(file, argp);
108*4882a593Smuzhiyun 	case SNDRV_TIMER_IOCTL_STATUS_COMPAT64:
109*4882a593Smuzhiyun 		return snd_timer_user_status64(file, argp);
110*4882a593Smuzhiyun 	}
111*4882a593Smuzhiyun 	return -ENOIOCTLCMD;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
snd_timer_user_ioctl_compat(struct file * file,unsigned int cmd,unsigned long arg)114*4882a593Smuzhiyun static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
115*4882a593Smuzhiyun 					unsigned long arg)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	struct snd_timer_user *tu = file->private_data;
118*4882a593Smuzhiyun 	long ret;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	mutex_lock(&tu->ioctl_lock);
121*4882a593Smuzhiyun 	ret = __snd_timer_user_ioctl_compat(file, cmd, arg);
122*4882a593Smuzhiyun 	mutex_unlock(&tu->ioctl_lock);
123*4882a593Smuzhiyun 	return ret;
124*4882a593Smuzhiyun }
125