Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/drivers/opl4/opl4_seq.c
10817 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 <sound/initval.h>
38
39
MODULE_AUTHOR("Clemens Ladisch <[email protected]>");
40
MODULE_DESCRIPTION("OPL4 wavetable synth driver");
41
MODULE_LICENSE("Dual BSD/GPL");
42
43
int volume_boost = 8;
44
45
module_param(volume_boost, int, 0644);
46
MODULE_PARM_DESC(volume_boost, "Additional volume for OPL4 wavetable sounds.");
47
48
static int snd_opl4_seq_use_inc(struct snd_opl4 *opl4)
49
{
50
if (!try_module_get(opl4->card->module))
51
return -EFAULT;
52
return 0;
53
}
54
55
static void snd_opl4_seq_use_dec(struct snd_opl4 *opl4)
56
{
57
module_put(opl4->card->module);
58
}
59
60
static int snd_opl4_seq_use(void *private_data, struct snd_seq_port_subscribe *info)
61
{
62
struct snd_opl4 *opl4 = private_data;
63
int err;
64
65
mutex_lock(&opl4->access_mutex);
66
67
if (opl4->used) {
68
mutex_unlock(&opl4->access_mutex);
69
return -EBUSY;
70
}
71
opl4->used++;
72
73
if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
74
err = snd_opl4_seq_use_inc(opl4);
75
if (err < 0) {
76
mutex_unlock(&opl4->access_mutex);
77
return err;
78
}
79
}
80
81
mutex_unlock(&opl4->access_mutex);
82
83
snd_opl4_synth_reset(opl4);
84
return 0;
85
}
86
87
static int snd_opl4_seq_unuse(void *private_data, struct snd_seq_port_subscribe *info)
88
{
89
struct snd_opl4 *opl4 = private_data;
90
91
snd_opl4_synth_shutdown(opl4);
92
93
mutex_lock(&opl4->access_mutex);
94
opl4->used--;
95
mutex_unlock(&opl4->access_mutex);
96
97
if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM)
98
snd_opl4_seq_use_dec(opl4);
99
return 0;
100
}
101
102
static struct snd_midi_op opl4_ops = {
103
.note_on = snd_opl4_note_on,
104
.note_off = snd_opl4_note_off,
105
.note_terminate = snd_opl4_terminate_note,
106
.control = snd_opl4_control,
107
.sysex = snd_opl4_sysex,
108
};
109
110
static int snd_opl4_seq_event_input(struct snd_seq_event *ev, int direct,
111
void *private_data, int atomic, int hop)
112
{
113
struct snd_opl4 *opl4 = private_data;
114
115
snd_midi_process_event(&opl4_ops, ev, opl4->chset);
116
return 0;
117
}
118
119
static void snd_opl4_seq_free_port(void *private_data)
120
{
121
struct snd_opl4 *opl4 = private_data;
122
123
snd_midi_channel_free_set(opl4->chset);
124
}
125
126
static int snd_opl4_seq_new_device(struct snd_seq_device *dev)
127
{
128
struct snd_opl4 *opl4;
129
int client;
130
struct snd_seq_port_callback pcallbacks;
131
132
opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
133
if (!opl4)
134
return -EINVAL;
135
136
if (snd_yrw801_detect(opl4) < 0)
137
return -ENODEV;
138
139
opl4->chset = snd_midi_channel_alloc_set(16);
140
if (!opl4->chset)
141
return -ENOMEM;
142
opl4->chset->private_data = opl4;
143
144
/* allocate new client */
145
client = snd_seq_create_kernel_client(opl4->card, opl4->seq_dev_num,
146
"OPL4 Wavetable");
147
if (client < 0) {
148
snd_midi_channel_free_set(opl4->chset);
149
return client;
150
}
151
opl4->seq_client = client;
152
opl4->chset->client = client;
153
154
/* create new port */
155
memset(&pcallbacks, 0, sizeof(pcallbacks));
156
pcallbacks.owner = THIS_MODULE;
157
pcallbacks.use = snd_opl4_seq_use;
158
pcallbacks.unuse = snd_opl4_seq_unuse;
159
pcallbacks.event_input = snd_opl4_seq_event_input;
160
pcallbacks.private_free = snd_opl4_seq_free_port;
161
pcallbacks.private_data = opl4;
162
163
opl4->chset->port = snd_seq_event_port_attach(client, &pcallbacks,
164
SNDRV_SEQ_PORT_CAP_WRITE |
165
SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
166
SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
167
SNDRV_SEQ_PORT_TYPE_MIDI_GM |
168
SNDRV_SEQ_PORT_TYPE_HARDWARE |
169
SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
170
16, 24,
171
"OPL4 Wavetable Port");
172
if (opl4->chset->port < 0) {
173
int err = opl4->chset->port;
174
snd_midi_channel_free_set(opl4->chset);
175
snd_seq_delete_kernel_client(client);
176
opl4->seq_client = -1;
177
return err;
178
}
179
return 0;
180
}
181
182
static int snd_opl4_seq_delete_device(struct snd_seq_device *dev)
183
{
184
struct snd_opl4 *opl4;
185
186
opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
187
if (!opl4)
188
return -EINVAL;
189
190
if (opl4->seq_client >= 0) {
191
snd_seq_delete_kernel_client(opl4->seq_client);
192
opl4->seq_client = -1;
193
}
194
return 0;
195
}
196
197
static int __init alsa_opl4_synth_init(void)
198
{
199
static struct snd_seq_dev_ops ops = {
200
snd_opl4_seq_new_device,
201
snd_opl4_seq_delete_device
202
};
203
204
return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL4, &ops,
205
sizeof(struct snd_opl4 *));
206
}
207
208
static void __exit alsa_opl4_synth_exit(void)
209
{
210
snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL4);
211
}
212
213
module_init(alsa_opl4_synth_init)
214
module_exit(alsa_opl4_synth_exit)
215
216