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