linux/sound/synth/emux/emux_hwdep.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Interface for hwdep device
   4 *
   5 *  Copyright (C) 2004 Takashi Iwai <tiwai@suse.de>
   6 */
   7
   8#include <sound/core.h>
   9#include <sound/hwdep.h>
  10#include <linux/uaccess.h>
  11#include <linux/nospec.h>
  12#include "emux_voice.h"
  13
  14#define TMP_CLIENT_ID   0x1001
  15
  16/*
  17 * load patch
  18 */
  19static int
  20snd_emux_hwdep_load_patch(struct snd_emux *emu, void __user *arg)
  21{
  22        int err;
  23        struct soundfont_patch_info patch;
  24
  25        if (copy_from_user(&patch, arg, sizeof(patch)))
  26                return -EFAULT;
  27
  28        if (patch.key == GUS_PATCH)
  29                return snd_soundfont_load_guspatch(emu->sflist, arg,
  30                                                   patch.len + sizeof(patch),
  31                                                   TMP_CLIENT_ID);
  32
  33        if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
  34            patch.type <= SNDRV_SFNT_PROBE_DATA) {
  35                err = snd_soundfont_load(emu->sflist, arg, patch.len + sizeof(patch), TMP_CLIENT_ID);
  36                if (err < 0)
  37                        return err;
  38        } else {
  39                if (emu->ops.load_fx)
  40                        return emu->ops.load_fx(emu, patch.type, patch.optarg, arg, patch.len + sizeof(patch));
  41                else
  42                        return -EINVAL;
  43        }
  44        return 0;
  45}
  46
  47/*
  48 * set misc mode
  49 */
  50static int
  51snd_emux_hwdep_misc_mode(struct snd_emux *emu, void __user *arg)
  52{
  53        struct snd_emux_misc_mode info;
  54        int i;
  55
  56        if (copy_from_user(&info, arg, sizeof(info)))
  57                return -EFAULT;
  58        if (info.mode < 0 || info.mode >= EMUX_MD_END)
  59                return -EINVAL;
  60        info.mode = array_index_nospec(info.mode, EMUX_MD_END);
  61
  62        if (info.port < 0) {
  63                for (i = 0; i < emu->num_ports; i++)
  64                        emu->portptrs[i]->ctrls[info.mode] = info.value;
  65        } else {
  66                if (info.port < emu->num_ports) {
  67                        info.port = array_index_nospec(info.port, emu->num_ports);
  68                        emu->portptrs[info.port]->ctrls[info.mode] = info.value;
  69                }
  70        }
  71        return 0;
  72}
  73
  74
  75/*
  76 * ioctl
  77 */
  78static int
  79snd_emux_hwdep_ioctl(struct snd_hwdep * hw, struct file *file,
  80                     unsigned int cmd, unsigned long arg)
  81{
  82        struct snd_emux *emu = hw->private_data;
  83
  84        switch (cmd) {
  85        case SNDRV_EMUX_IOCTL_VERSION:
  86                return put_user(SNDRV_EMUX_VERSION, (unsigned int __user *)arg);
  87        case SNDRV_EMUX_IOCTL_LOAD_PATCH:
  88                return snd_emux_hwdep_load_patch(emu, (void __user *)arg);
  89        case SNDRV_EMUX_IOCTL_RESET_SAMPLES:
  90                snd_soundfont_remove_samples(emu->sflist);
  91                break;
  92        case SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES:
  93                snd_soundfont_remove_unlocked(emu->sflist);
  94                break;
  95        case SNDRV_EMUX_IOCTL_MEM_AVAIL:
  96                if (emu->memhdr) {
  97                        int size = snd_util_mem_avail(emu->memhdr);
  98                        return put_user(size, (unsigned int __user *)arg);
  99                }
 100                break;
 101        case SNDRV_EMUX_IOCTL_MISC_MODE:
 102                return snd_emux_hwdep_misc_mode(emu, (void __user *)arg);
 103        }
 104
 105        return 0;
 106}
 107
 108
 109/*
 110 * register hwdep device
 111 */
 112
 113int
 114snd_emux_init_hwdep(struct snd_emux *emu)
 115{
 116        struct snd_hwdep *hw;
 117        int err;
 118
 119        if ((err = snd_hwdep_new(emu->card, SNDRV_EMUX_HWDEP_NAME, emu->hwdep_idx, &hw)) < 0)
 120                return err;
 121        emu->hwdep = hw;
 122        strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME);
 123        hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE;
 124        hw->ops.ioctl = snd_emux_hwdep_ioctl;
 125        /* The ioctl parameter types are compatible between 32- and
 126         * 64-bit architectures, so use the same function. */
 127        hw->ops.ioctl_compat = snd_emux_hwdep_ioctl;
 128        hw->exclusive = 1;
 129        hw->private_data = emu;
 130        if ((err = snd_card_register(emu->card)) < 0)
 131                return err;
 132
 133        return 0;
 134}
 135
 136
 137/*
 138 * unregister
 139 */
 140void
 141snd_emux_delete_hwdep(struct snd_emux *emu)
 142{
 143        if (emu->hwdep) {
 144                snd_device_free(emu->card, emu->hwdep);
 145                emu->hwdep = NULL;
 146        }
 147}
 148