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