linux/sound/core/timer_compat.c
<<
>>
Prefs
   1/*
   2 *   32bit -> 64bit ioctl wrapper for timer API
   3 *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
   4 *
   5 *   This program is free software; you can redistribute it and/or modify
   6 *   it under the terms of the GNU General Public License as published by
   7 *   the Free Software Foundation; either version 2 of the License, or
   8 *   (at your option) any later version.
   9 *
  10 *   This program is distributed in the hope that it will be useful,
  11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 *   GNU General Public License for more details.
  14 *
  15 *   You should have received a copy of the GNU General Public License
  16 *   along with this program; if not, write to the Free Software
  17 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18 *
  19 */
  20
  21/* This file included from timer.c */
  22
  23#include <linux/compat.h>
  24
  25/*
  26 * ILP32/LP64 has different size for 'long' type. Additionally, the size
  27 * of storage alignment differs depending on architectures. Here, '__packed'
  28 * qualifier is used so that the size of this structure is multiple of 4 and
  29 * it fits to any architectures with 32 bit storage alignment.
  30 */
  31struct snd_timer_gparams32 {
  32        struct snd_timer_id tid;
  33        u32 period_num;
  34        u32 period_den;
  35        unsigned char reserved[32];
  36} __packed;
  37
  38struct snd_timer_info32 {
  39        u32 flags;
  40        s32 card;
  41        unsigned char id[64];
  42        unsigned char name[80];
  43        u32 reserved0;
  44        u32 resolution;
  45        unsigned char reserved[64];
  46};
  47
  48static int snd_timer_user_gparams_compat(struct file *file,
  49                                        struct snd_timer_gparams32 __user *user)
  50{
  51        struct snd_timer_gparams gparams;
  52
  53        if (copy_from_user(&gparams.tid, &user->tid, sizeof(gparams.tid)) ||
  54            get_user(gparams.period_num, &user->period_num) ||
  55            get_user(gparams.period_den, &user->period_den))
  56                return -EFAULT;
  57
  58        return timer_set_gparams(&gparams);
  59}
  60
  61static int snd_timer_user_info_compat(struct file *file,
  62                                      struct snd_timer_info32 __user *_info)
  63{
  64        struct snd_timer_user *tu;
  65        struct snd_timer_info32 info;
  66        struct snd_timer *t;
  67
  68        tu = file->private_data;
  69        if (snd_BUG_ON(!tu->timeri))
  70                return -ENXIO;
  71        t = tu->timeri->timer;
  72        if (snd_BUG_ON(!t))
  73                return -ENXIO;
  74        memset(&info, 0, sizeof(info));
  75        info.card = t->card ? t->card->number : -1;
  76        if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
  77                info.flags |= SNDRV_TIMER_FLG_SLAVE;
  78        strlcpy(info.id, t->id, sizeof(info.id));
  79        strlcpy(info.name, t->name, sizeof(info.name));
  80        info.resolution = t->hw.resolution;
  81        if (copy_to_user(_info, &info, sizeof(*_info)))
  82                return -EFAULT;
  83        return 0;
  84}
  85
  86struct snd_timer_status32 {
  87        struct compat_timespec tstamp;
  88        u32 resolution;
  89        u32 lost;
  90        u32 overrun;
  91        u32 queue;
  92        unsigned char reserved[64];
  93};
  94
  95static int snd_timer_user_status_compat(struct file *file,
  96                                        struct snd_timer_status32 __user *_status)
  97{
  98        struct snd_timer_user *tu;
  99        struct snd_timer_status32 status;
 100        
 101        tu = file->private_data;
 102        if (snd_BUG_ON(!tu->timeri))
 103                return -ENXIO;
 104        memset(&status, 0, sizeof(status));
 105        status.tstamp.tv_sec = tu->tstamp.tv_sec;
 106        status.tstamp.tv_nsec = tu->tstamp.tv_nsec;
 107        status.resolution = snd_timer_resolution(tu->timeri);
 108        status.lost = tu->timeri->lost;
 109        status.overrun = tu->overrun;
 110        spin_lock_irq(&tu->qlock);
 111        status.queue = tu->qused;
 112        spin_unlock_irq(&tu->qlock);
 113        if (copy_to_user(_status, &status, sizeof(status)))
 114                return -EFAULT;
 115        return 0;
 116}
 117
 118#ifdef CONFIG_X86_X32
 119/* X32 ABI has the same struct as x86-64 */
 120#define snd_timer_user_status_x32(file, s) \
 121        snd_timer_user_status(file, s)
 122#endif /* CONFIG_X86_X32 */
 123
 124/*
 125 */
 126
 127enum {
 128        SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32),
 129        SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32),
 130        SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32),
 131#ifdef CONFIG_X86_X32
 132        SNDRV_TIMER_IOCTL_STATUS_X32 = _IOW('T', 0x14, struct snd_timer_status),
 133#endif /* CONFIG_X86_X32 */
 134};
 135
 136static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 137{
 138        void __user *argp = compat_ptr(arg);
 139
 140        switch (cmd) {
 141        case SNDRV_TIMER_IOCTL_PVERSION:
 142        case SNDRV_TIMER_IOCTL_TREAD:
 143        case SNDRV_TIMER_IOCTL_GINFO:
 144        case SNDRV_TIMER_IOCTL_GSTATUS:
 145        case SNDRV_TIMER_IOCTL_SELECT:
 146        case SNDRV_TIMER_IOCTL_PARAMS:
 147        case SNDRV_TIMER_IOCTL_START:
 148        case SNDRV_TIMER_IOCTL_START_OLD:
 149        case SNDRV_TIMER_IOCTL_STOP:
 150        case SNDRV_TIMER_IOCTL_STOP_OLD:
 151        case SNDRV_TIMER_IOCTL_CONTINUE:
 152        case SNDRV_TIMER_IOCTL_CONTINUE_OLD:
 153        case SNDRV_TIMER_IOCTL_PAUSE:
 154        case SNDRV_TIMER_IOCTL_PAUSE_OLD:
 155        case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
 156                return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
 157        case SNDRV_TIMER_IOCTL_GPARAMS32:
 158                return snd_timer_user_gparams_compat(file, argp);
 159        case SNDRV_TIMER_IOCTL_INFO32:
 160                return snd_timer_user_info_compat(file, argp);
 161        case SNDRV_TIMER_IOCTL_STATUS32:
 162                return snd_timer_user_status_compat(file, argp);
 163#ifdef CONFIG_X86_X32
 164        case SNDRV_TIMER_IOCTL_STATUS_X32:
 165                return snd_timer_user_status_x32(file, argp);
 166#endif /* CONFIG_X86_X32 */
 167        }
 168        return -ENOIOCTLCMD;
 169}
 170