Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/drivers/opl4/opl4_seq.c
29266 views
1
/*
2
* OPL4 sequencer functions
3
*
4
* Copyright (c) 2003 by Clemens Ladisch <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions, and the following disclaimer,
12
* without modification.
13
* 2. The name of the author may not be used to endorse or promote products
14
* derived from this software without specific prior written permission.
15
*
16
* Alternatively, this software may be distributed and/or modified under the
17
* terms of the GNU General Public License as published by the Free Software
18
* Foundation; either version 2 of the License, or (at your option) any later
19
* version.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
25
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*/
33
34
#include "opl4_local.h"
35
#include <linux/init.h>
36
#include <linux/moduleparam.h>
37
#include <linux/module.h>
38
#include <sound/initval.h>
39
40
MODULE_AUTHOR("Clemens Ladisch <[email protected]>");
41
MODULE_DESCRIPTION("OPL4 wavetable synth driver");
42
MODULE_LICENSE("Dual BSD/GPL");
43
44
int volume_boost = 8;
45
46
module_param(volume_boost, int, 0644);
47
MODULE_PARM_DESC(volume_boost, "Additional volume for OPL4 wavetable sounds.");
48
49
static int snd_opl4_seq_use_inc(struct snd_opl4 *opl4)
50
{
51
if (!try_module_get(opl4->card->module))
52
return -EFAULT;
53
return 0;
54
}
55
56
static void snd_opl4_seq_use_dec(struct snd_opl4 *opl4)
57
{
58
module_put(opl4->card->module);
59
}
60
61
static int snd_opl4_seq_use(void *private_data, struct snd_seq_port_subscribe *info)
62
{
63
struct snd_opl4 *opl4 = private_data;
64
int err;
65
66
scoped_guard(mutex, &opl4->access_mutex) {
67
if (opl4->used)
68
return -EBUSY;
69
opl4->used++;
70
71
if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
72
err = snd_opl4_seq_use_inc(opl4);
73
if (err < 0)
74
return err;
75
}
76
}
77
78
snd_opl4_synth_reset(opl4);
79
return 0;
80
}
81
82
static int snd_opl4_seq_unuse(void *private_data, struct snd_seq_port_subscribe *info)
83
{
84
struct snd_opl4 *opl4 = private_data;
85
86
snd_opl4_synth_shutdown(opl4);
87
88
scoped_guard(mutex, &opl4->access_mutex) {
89
opl4->used--;
90
}
91
92
if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM)
93
snd_opl4_seq_use_dec(opl4);
94
return 0;
95
}
96
97
static const struct snd_midi_op opl4_ops = {
98
.note_on = snd_opl4_note_on,
99
.note_off = snd_opl4_note_off,
100
.note_terminate = snd_opl4_terminate_note,
101
.control = snd_opl4_control,
102
.sysex = snd_opl4_sysex,
103
};
104
105
static int snd_opl4_seq_event_input(struct snd_seq_event *ev, int direct,
106
void *private_data, int atomic, int hop)
107
{
108
struct snd_opl4 *opl4 = private_data;
109
110
snd_midi_process_event(&opl4_ops, ev, opl4->chset);
111
return 0;
112
}
113
114
static void snd_opl4_seq_free_port(void *private_data)
115
{
116
struct snd_opl4 *opl4 = private_data;
117
118
snd_midi_channel_free_set(opl4->chset);
119
}
120
121
static int snd_opl4_seq_probe(struct device *_dev)
122
{
123
struct snd_seq_device *dev = to_seq_dev(_dev);
124
struct snd_opl4 *opl4;
125
int client;
126
struct snd_seq_port_callback pcallbacks;
127
128
opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
129
if (!opl4)
130
return -EINVAL;
131
132
if (snd_yrw801_detect(opl4) < 0)
133
return -ENODEV;
134
135
opl4->chset = snd_midi_channel_alloc_set(16);
136
if (!opl4->chset)
137
return -ENOMEM;
138
opl4->chset->private_data = opl4;
139
140
/* allocate new client */
141
client = snd_seq_create_kernel_client(opl4->card, opl4->seq_dev_num,
142
"OPL4 Wavetable");
143
if (client < 0) {
144
snd_midi_channel_free_set(opl4->chset);
145
return client;
146
}
147
opl4->seq_client = client;
148
opl4->chset->client = client;
149
150
/* create new port */
151
memset(&pcallbacks, 0, sizeof(pcallbacks));
152
pcallbacks.owner = THIS_MODULE;
153
pcallbacks.use = snd_opl4_seq_use;
154
pcallbacks.unuse = snd_opl4_seq_unuse;
155
pcallbacks.event_input = snd_opl4_seq_event_input;
156
pcallbacks.private_free = snd_opl4_seq_free_port;
157
pcallbacks.private_data = opl4;
158
159
opl4->chset->port = snd_seq_event_port_attach(client, &pcallbacks,
160
SNDRV_SEQ_PORT_CAP_WRITE |
161
SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
162
SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
163
SNDRV_SEQ_PORT_TYPE_MIDI_GM |
164
SNDRV_SEQ_PORT_TYPE_HARDWARE |
165
SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
166
16, 24,
167
"OPL4 Wavetable Port");
168
if (opl4->chset->port < 0) {
169
int err = opl4->chset->port;
170
snd_midi_channel_free_set(opl4->chset);
171
snd_seq_delete_kernel_client(client);
172
opl4->seq_client = -1;
173
return err;
174
}
175
return 0;
176
}
177
178
static int snd_opl4_seq_remove(struct device *_dev)
179
{
180
struct snd_seq_device *dev = to_seq_dev(_dev);
181
struct snd_opl4 *opl4;
182
183
opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
184
if (!opl4)
185
return -EINVAL;
186
187
if (opl4->seq_client >= 0) {
188
snd_seq_delete_kernel_client(opl4->seq_client);
189
opl4->seq_client = -1;
190
}
191
return 0;
192
}
193
194
static struct snd_seq_driver opl4_seq_driver = {
195
.driver = {
196
.name = KBUILD_MODNAME,
197
.probe = snd_opl4_seq_probe,
198
.remove = snd_opl4_seq_remove,
199
},
200
.id = SNDRV_SEQ_DEV_ID_OPL4,
201
.argsize = sizeof(struct snd_opl4 *),
202
};
203
204
module_snd_seq_driver(opl4_seq_driver);
205
206