Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/drivers/opl4/opl4_seq.c
26451 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
mutex_lock(&opl4->access_mutex);
67
68
if (opl4->used) {
69
mutex_unlock(&opl4->access_mutex);
70
return -EBUSY;
71
}
72
opl4->used++;
73
74
if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
75
err = snd_opl4_seq_use_inc(opl4);
76
if (err < 0) {
77
mutex_unlock(&opl4->access_mutex);
78
return err;
79
}
80
}
81
82
mutex_unlock(&opl4->access_mutex);
83
84
snd_opl4_synth_reset(opl4);
85
return 0;
86
}
87
88
static int snd_opl4_seq_unuse(void *private_data, struct snd_seq_port_subscribe *info)
89
{
90
struct snd_opl4 *opl4 = private_data;
91
92
snd_opl4_synth_shutdown(opl4);
93
94
mutex_lock(&opl4->access_mutex);
95
opl4->used--;
96
mutex_unlock(&opl4->access_mutex);
97
98
if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM)
99
snd_opl4_seq_use_dec(opl4);
100
return 0;
101
}
102
103
static const struct snd_midi_op opl4_ops = {
104
.note_on = snd_opl4_note_on,
105
.note_off = snd_opl4_note_off,
106
.note_terminate = snd_opl4_terminate_note,
107
.control = snd_opl4_control,
108
.sysex = snd_opl4_sysex,
109
};
110
111
static int snd_opl4_seq_event_input(struct snd_seq_event *ev, int direct,
112
void *private_data, int atomic, int hop)
113
{
114
struct snd_opl4 *opl4 = private_data;
115
116
snd_midi_process_event(&opl4_ops, ev, opl4->chset);
117
return 0;
118
}
119
120
static void snd_opl4_seq_free_port(void *private_data)
121
{
122
struct snd_opl4 *opl4 = private_data;
123
124
snd_midi_channel_free_set(opl4->chset);
125
}
126
127
static int snd_opl4_seq_probe(struct device *_dev)
128
{
129
struct snd_seq_device *dev = to_seq_dev(_dev);
130
struct snd_opl4 *opl4;
131
int client;
132
struct snd_seq_port_callback pcallbacks;
133
134
opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
135
if (!opl4)
136
return -EINVAL;
137
138
if (snd_yrw801_detect(opl4) < 0)
139
return -ENODEV;
140
141
opl4->chset = snd_midi_channel_alloc_set(16);
142
if (!opl4->chset)
143
return -ENOMEM;
144
opl4->chset->private_data = opl4;
145
146
/* allocate new client */
147
client = snd_seq_create_kernel_client(opl4->card, opl4->seq_dev_num,
148
"OPL4 Wavetable");
149
if (client < 0) {
150
snd_midi_channel_free_set(opl4->chset);
151
return client;
152
}
153
opl4->seq_client = client;
154
opl4->chset->client = client;
155
156
/* create new port */
157
memset(&pcallbacks, 0, sizeof(pcallbacks));
158
pcallbacks.owner = THIS_MODULE;
159
pcallbacks.use = snd_opl4_seq_use;
160
pcallbacks.unuse = snd_opl4_seq_unuse;
161
pcallbacks.event_input = snd_opl4_seq_event_input;
162
pcallbacks.private_free = snd_opl4_seq_free_port;
163
pcallbacks.private_data = opl4;
164
165
opl4->chset->port = snd_seq_event_port_attach(client, &pcallbacks,
166
SNDRV_SEQ_PORT_CAP_WRITE |
167
SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
168
SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
169
SNDRV_SEQ_PORT_TYPE_MIDI_GM |
170
SNDRV_SEQ_PORT_TYPE_HARDWARE |
171
SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
172
16, 24,
173
"OPL4 Wavetable Port");
174
if (opl4->chset->port < 0) {
175
int err = opl4->chset->port;
176
snd_midi_channel_free_set(opl4->chset);
177
snd_seq_delete_kernel_client(client);
178
opl4->seq_client = -1;
179
return err;
180
}
181
return 0;
182
}
183
184
static int snd_opl4_seq_remove(struct device *_dev)
185
{
186
struct snd_seq_device *dev = to_seq_dev(_dev);
187
struct snd_opl4 *opl4;
188
189
opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
190
if (!opl4)
191
return -EINVAL;
192
193
if (opl4->seq_client >= 0) {
194
snd_seq_delete_kernel_client(opl4->seq_client);
195
opl4->seq_client = -1;
196
}
197
return 0;
198
}
199
200
static struct snd_seq_driver opl4_seq_driver = {
201
.driver = {
202
.name = KBUILD_MODNAME,
203
.probe = snd_opl4_seq_probe,
204
.remove = snd_opl4_seq_remove,
205
},
206
.id = SNDRV_SEQ_DEV_ID_OPL4,
207
.argsize = sizeof(struct snd_opl4 *),
208
};
209
210
module_snd_seq_driver(opl4_seq_driver);
211
212