Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/synth/emux/emux_hwdep.c
29266 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Interface for hwdep device
4
*
5
* Copyright (C) 2004 Takashi Iwai <[email protected]>
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
*/
19
static int
20
snd_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->card, emu->sflist, arg,
30
patch.len + sizeof(patch));
31
32
if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
33
patch.type <= SNDRV_SFNT_PROBE_DATA) {
34
err = snd_soundfont_load(emu->card, emu->sflist, arg,
35
patch.len + sizeof(patch),
36
TMP_CLIENT_ID);
37
if (err < 0)
38
return err;
39
} else {
40
if (emu->ops.load_fx)
41
return emu->ops.load_fx(emu, patch.type, patch.optarg, arg, patch.len + sizeof(patch));
42
else
43
return -EINVAL;
44
}
45
return 0;
46
}
47
48
/*
49
* set misc mode
50
*/
51
static int
52
snd_emux_hwdep_misc_mode(struct snd_emux *emu, void __user *arg)
53
{
54
struct snd_emux_misc_mode info;
55
int i;
56
57
if (copy_from_user(&info, arg, sizeof(info)))
58
return -EFAULT;
59
if (info.mode < 0 || info.mode >= EMUX_MD_END)
60
return -EINVAL;
61
info.mode = array_index_nospec(info.mode, EMUX_MD_END);
62
63
if (info.port < 0) {
64
for (i = 0; i < emu->num_ports; i++)
65
emu->portptrs[i]->ctrls[info.mode] = info.value;
66
} else {
67
if (info.port < emu->num_ports) {
68
info.port = array_index_nospec(info.port, emu->num_ports);
69
emu->portptrs[info.port]->ctrls[info.mode] = info.value;
70
}
71
}
72
return 0;
73
}
74
75
76
/*
77
* ioctl
78
*/
79
static int
80
snd_emux_hwdep_ioctl(struct snd_hwdep * hw, struct file *file,
81
unsigned int cmd, unsigned long arg)
82
{
83
struct snd_emux *emu = hw->private_data;
84
85
switch (cmd) {
86
case SNDRV_EMUX_IOCTL_VERSION:
87
return put_user(SNDRV_EMUX_VERSION, (unsigned int __user *)arg);
88
case SNDRV_EMUX_IOCTL_LOAD_PATCH:
89
return snd_emux_hwdep_load_patch(emu, (void __user *)arg);
90
case SNDRV_EMUX_IOCTL_RESET_SAMPLES:
91
snd_soundfont_remove_samples(emu->sflist);
92
break;
93
case SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES:
94
snd_soundfont_remove_unlocked(emu->sflist);
95
break;
96
case SNDRV_EMUX_IOCTL_MEM_AVAIL:
97
if (emu->memhdr) {
98
int size = snd_util_mem_avail(emu->memhdr);
99
return put_user(size, (unsigned int __user *)arg);
100
}
101
break;
102
case SNDRV_EMUX_IOCTL_MISC_MODE:
103
return snd_emux_hwdep_misc_mode(emu, (void __user *)arg);
104
}
105
106
return 0;
107
}
108
109
110
/*
111
* register hwdep device
112
*/
113
114
int
115
snd_emux_init_hwdep(struct snd_emux *emu)
116
{
117
struct snd_hwdep *hw;
118
int err;
119
120
err = snd_hwdep_new(emu->card, SNDRV_EMUX_HWDEP_NAME, emu->hwdep_idx, &hw);
121
if (err < 0)
122
return err;
123
emu->hwdep = hw;
124
strscpy(hw->name, SNDRV_EMUX_HWDEP_NAME);
125
hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE;
126
hw->ops.ioctl = snd_emux_hwdep_ioctl;
127
/* The ioctl parameter types are compatible between 32- and
128
* 64-bit architectures, so use the same function. */
129
hw->ops.ioctl_compat = snd_emux_hwdep_ioctl;
130
hw->exclusive = 1;
131
hw->private_data = emu;
132
err = snd_card_register(emu->card);
133
if (err < 0)
134
return err;
135
136
return 0;
137
}
138
139
140
/*
141
* unregister
142
*/
143
void
144
snd_emux_delete_hwdep(struct snd_emux *emu)
145
{
146
if (emu->hwdep) {
147
snd_device_free(emu->card, emu->hwdep);
148
emu->hwdep = NULL;
149
}
150
}
151
152