Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/synth/emux/emux_oss.c
29269 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Interface for OSS sequencer emulation
4
*
5
* Copyright (C) 1999 Takashi Iwai <[email protected]>
6
*
7
* Changes
8
* 19990227 Steve Ratcliffe Made separate file and merged in latest
9
* midi emulation.
10
*/
11
12
13
#include <linux/export.h>
14
#include <linux/uaccess.h>
15
#include <sound/core.h>
16
#include "emux_voice.h"
17
#include <sound/asoundef.h>
18
19
static int snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure);
20
static int snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg);
21
static int snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
22
unsigned long ioarg);
23
static int snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
24
const char __user *buf, int offs, int count);
25
static int snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg);
26
static int snd_emux_event_oss_input(struct snd_seq_event *ev, int direct,
27
void *private, int atomic, int hop);
28
static void reset_port_mode(struct snd_emux_port *port, int midi_mode);
29
static void emuspec_control(struct snd_emux *emu, struct snd_emux_port *port,
30
int cmd, unsigned char *event, int atomic, int hop);
31
static void gusspec_control(struct snd_emux *emu, struct snd_emux_port *port,
32
int cmd, unsigned char *event, int atomic, int hop);
33
static void fake_event(struct snd_emux *emu, struct snd_emux_port *port,
34
int ch, int param, int val, int atomic, int hop);
35
36
/* operators */
37
static const struct snd_seq_oss_callback oss_callback = {
38
.owner = THIS_MODULE,
39
.open = snd_emux_open_seq_oss,
40
.close = snd_emux_close_seq_oss,
41
.ioctl = snd_emux_ioctl_seq_oss,
42
.load_patch = snd_emux_load_patch_seq_oss,
43
.reset = snd_emux_reset_seq_oss,
44
};
45
46
47
/*
48
* register OSS synth
49
*/
50
51
void
52
snd_emux_init_seq_oss(struct snd_emux *emu)
53
{
54
struct snd_seq_oss_reg *arg;
55
struct snd_seq_device *dev;
56
57
/* using device#1 here for avoiding conflicts with OPL3 */
58
if (snd_seq_device_new(emu->card, 1, SNDRV_SEQ_DEV_ID_OSS,
59
sizeof(struct snd_seq_oss_reg), &dev) < 0)
60
return;
61
62
emu->oss_synth = dev;
63
strscpy(dev->name, emu->name);
64
arg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
65
arg->type = SYNTH_TYPE_SAMPLE;
66
arg->subtype = SAMPLE_TYPE_AWE32;
67
arg->nvoices = emu->max_voices;
68
arg->oper = oss_callback;
69
arg->private_data = emu;
70
71
/* register to OSS synth table */
72
snd_device_register(emu->card, dev);
73
}
74
75
76
/*
77
* unregister
78
*/
79
void
80
snd_emux_detach_seq_oss(struct snd_emux *emu)
81
{
82
if (emu->oss_synth) {
83
snd_device_free(emu->card, emu->oss_synth);
84
emu->oss_synth = NULL;
85
}
86
}
87
88
89
/* use port number as a unique soundfont client number */
90
#define SF_CLIENT_NO(p) ((p) + 0x1000)
91
92
/*
93
* open port for OSS sequencer
94
*/
95
static int
96
snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
97
{
98
struct snd_emux *emu;
99
struct snd_emux_port *p;
100
struct snd_seq_port_callback callback;
101
char tmpname[64];
102
103
emu = closure;
104
if (snd_BUG_ON(!arg || !emu))
105
return -ENXIO;
106
107
if (!snd_emux_inc_count(emu))
108
return -EFAULT;
109
110
memset(&callback, 0, sizeof(callback));
111
callback.owner = THIS_MODULE;
112
callback.event_input = snd_emux_event_oss_input;
113
114
sprintf(tmpname, "%s OSS Port", emu->name);
115
p = snd_emux_create_port(emu, tmpname, 32,
116
1, &callback);
117
if (p == NULL) {
118
dev_err(emu->card->dev, "can't create port\n");
119
snd_emux_dec_count(emu);
120
return -ENOMEM;
121
}
122
123
/* fill the argument data */
124
arg->private_data = p;
125
arg->addr.client = p->chset.client;
126
arg->addr.port = p->chset.port;
127
p->oss_arg = arg;
128
129
reset_port_mode(p, arg->seq_mode);
130
131
snd_emux_reset_port(p);
132
return 0;
133
}
134
135
136
#define DEFAULT_DRUM_FLAGS ((1<<9) | (1<<25))
137
138
/*
139
* reset port mode
140
*/
141
static void
142
reset_port_mode(struct snd_emux_port *port, int midi_mode)
143
{
144
if (midi_mode) {
145
port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_MIDI;
146
port->drum_flags = DEFAULT_DRUM_FLAGS;
147
port->volume_atten = 0;
148
port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_KEYPRESS;
149
} else {
150
port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_SYNTH;
151
port->drum_flags = 0;
152
port->volume_atten = 32;
153
port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS;
154
}
155
}
156
157
158
/*
159
* close port
160
*/
161
static int
162
snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg)
163
{
164
struct snd_emux *emu;
165
struct snd_emux_port *p;
166
167
if (snd_BUG_ON(!arg))
168
return -ENXIO;
169
p = arg->private_data;
170
if (snd_BUG_ON(!p))
171
return -ENXIO;
172
173
emu = p->emu;
174
if (snd_BUG_ON(!emu))
175
return -ENXIO;
176
177
snd_emux_sounds_off_all(p);
178
snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port));
179
snd_seq_event_port_detach(p->chset.client, p->chset.port);
180
snd_emux_dec_count(emu);
181
182
return 0;
183
}
184
185
186
/*
187
* load patch
188
*/
189
static int
190
snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
191
const char __user *buf, int offs, int count)
192
{
193
struct snd_emux *emu;
194
struct snd_emux_port *p;
195
int rc;
196
197
if (snd_BUG_ON(!arg))
198
return -ENXIO;
199
p = arg->private_data;
200
if (snd_BUG_ON(!p))
201
return -ENXIO;
202
203
emu = p->emu;
204
if (snd_BUG_ON(!emu))
205
return -ENXIO;
206
207
if (format == GUS_PATCH)
208
rc = snd_soundfont_load_guspatch(emu->card, emu->sflist, buf, count);
209
else if (format == SNDRV_OSS_SOUNDFONT_PATCH) {
210
struct soundfont_patch_info patch;
211
if (count < (int)sizeof(patch))
212
return -EINVAL;
213
if (copy_from_user(&patch, buf, sizeof(patch)))
214
return -EFAULT;
215
if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
216
patch.type <= SNDRV_SFNT_PROBE_DATA)
217
rc = snd_soundfont_load(emu->card, emu->sflist, buf,
218
count,
219
SF_CLIENT_NO(p->chset.port));
220
else {
221
if (emu->ops.load_fx)
222
rc = emu->ops.load_fx(emu, patch.type,
223
patch.optarg, buf, count);
224
else
225
rc = -EINVAL;
226
}
227
} else
228
rc = 0;
229
return rc;
230
}
231
232
233
/*
234
* ioctl
235
*/
236
static int
237
snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned long ioarg)
238
{
239
struct snd_emux_port *p;
240
struct snd_emux *emu;
241
242
if (snd_BUG_ON(!arg))
243
return -ENXIO;
244
p = arg->private_data;
245
if (snd_BUG_ON(!p))
246
return -ENXIO;
247
248
emu = p->emu;
249
if (snd_BUG_ON(!emu))
250
return -ENXIO;
251
252
switch (cmd) {
253
case SNDCTL_SEQ_RESETSAMPLES:
254
snd_soundfont_remove_samples(emu->sflist);
255
return 0;
256
257
case SNDCTL_SYNTH_MEMAVL:
258
if (emu->memhdr)
259
return snd_util_mem_avail(emu->memhdr);
260
return 0;
261
}
262
263
return 0;
264
}
265
266
267
/*
268
* reset device
269
*/
270
static int
271
snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg)
272
{
273
struct snd_emux_port *p;
274
275
if (snd_BUG_ON(!arg))
276
return -ENXIO;
277
p = arg->private_data;
278
if (snd_BUG_ON(!p))
279
return -ENXIO;
280
snd_emux_reset_port(p);
281
return 0;
282
}
283
284
285
/*
286
* receive raw events: only SEQ_PRIVATE is accepted.
287
*/
288
static int
289
snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, void *private_data,
290
int atomic, int hop)
291
{
292
struct snd_emux *emu;
293
struct snd_emux_port *p;
294
unsigned char cmd, *data;
295
296
p = private_data;
297
if (snd_BUG_ON(!p))
298
return -EINVAL;
299
emu = p->emu;
300
if (snd_BUG_ON(!emu))
301
return -EINVAL;
302
if (ev->type != SNDRV_SEQ_EVENT_OSS)
303
return snd_emux_event_input(ev, direct, private_data, atomic, hop);
304
305
data = ev->data.raw8.d;
306
/* only SEQ_PRIVATE is accepted */
307
if (data[0] != 0xfe)
308
return 0;
309
cmd = data[2] & _EMUX_OSS_MODE_VALUE_MASK;
310
if (data[2] & _EMUX_OSS_MODE_FLAG)
311
emuspec_control(emu, p, cmd, data, atomic, hop);
312
else
313
gusspec_control(emu, p, cmd, data, atomic, hop);
314
return 0;
315
}
316
317
318
/*
319
* OSS/AWE driver specific h/w controls
320
*/
321
static void
322
emuspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd,
323
unsigned char *event, int atomic, int hop)
324
{
325
int voice;
326
unsigned short p1;
327
short p2;
328
int i;
329
struct snd_midi_channel *chan;
330
331
voice = event[3];
332
if (voice < 0 || voice >= port->chset.max_channels)
333
chan = NULL;
334
else
335
chan = &port->chset.channels[voice];
336
337
p1 = *(unsigned short *) &event[4];
338
p2 = *(short *) &event[6];
339
340
switch (cmd) {
341
#if 0 /* don't do this atomically */
342
case _EMUX_OSS_REMOVE_LAST_SAMPLES:
343
snd_soundfont_remove_unlocked(emu->sflist);
344
break;
345
#endif
346
case _EMUX_OSS_SEND_EFFECT:
347
if (chan)
348
snd_emux_send_effect_oss(port, chan, p1, p2);
349
break;
350
351
case _EMUX_OSS_TERMINATE_ALL:
352
snd_emux_terminate_all(emu);
353
break;
354
355
case _EMUX_OSS_TERMINATE_CHANNEL:
356
/*snd_emux_mute_channel(emu, chan);*/
357
break;
358
case _EMUX_OSS_RESET_CHANNEL:
359
/*snd_emux_channel_init(chset, chan);*/
360
break;
361
362
case _EMUX_OSS_RELEASE_ALL:
363
fake_event(emu, port, voice, MIDI_CTL_ALL_NOTES_OFF, 0, atomic, hop);
364
break;
365
case _EMUX_OSS_NOTEOFF_ALL:
366
fake_event(emu, port, voice, MIDI_CTL_ALL_SOUNDS_OFF, 0, atomic, hop);
367
break;
368
369
case _EMUX_OSS_INITIAL_VOLUME:
370
if (p2) {
371
port->volume_atten = (short)p1;
372
snd_emux_update_port(port, SNDRV_EMUX_UPDATE_VOLUME);
373
}
374
break;
375
376
case _EMUX_OSS_CHN_PRESSURE:
377
if (chan) {
378
chan->midi_pressure = p1;
379
snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_FMMOD|SNDRV_EMUX_UPDATE_FM2FRQ2);
380
}
381
break;
382
383
case _EMUX_OSS_CHANNEL_MODE:
384
reset_port_mode(port, p1);
385
snd_emux_reset_port(port);
386
break;
387
388
case _EMUX_OSS_DRUM_CHANNELS:
389
port->drum_flags = *(unsigned int*)&event[4];
390
for (i = 0; i < port->chset.max_channels; i++) {
391
chan = &port->chset.channels[i];
392
chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0;
393
}
394
break;
395
396
case _EMUX_OSS_MISC_MODE:
397
if (p1 < EMUX_MD_END)
398
port->ctrls[p1] = p2;
399
break;
400
case _EMUX_OSS_DEBUG_MODE:
401
break;
402
403
default:
404
if (emu->ops.oss_ioctl)
405
emu->ops.oss_ioctl(emu, cmd, p1, p2);
406
break;
407
}
408
}
409
410
/*
411
* GUS specific h/w controls
412
*/
413
414
#include <linux/ultrasound.h>
415
416
static void
417
gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd,
418
unsigned char *event, int atomic, int hop)
419
{
420
int voice;
421
unsigned short p1;
422
int plong;
423
struct snd_midi_channel *chan;
424
425
if (port->port_mode != SNDRV_EMUX_PORT_MODE_OSS_SYNTH)
426
return;
427
if (cmd == _GUS_NUMVOICES)
428
return;
429
voice = event[3];
430
if (voice < 0 || voice >= port->chset.max_channels)
431
return;
432
433
chan = &port->chset.channels[voice];
434
435
p1 = *(unsigned short *) &event[4];
436
plong = *(int*) &event[4];
437
438
switch (cmd) {
439
case _GUS_VOICESAMPLE:
440
chan->midi_program = p1;
441
return;
442
443
case _GUS_VOICEBALA:
444
/* 0 to 15 --> 0 to 127 */
445
chan->control[MIDI_CTL_MSB_PAN] = (int)p1 << 3;
446
snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PAN);
447
return;
448
449
case _GUS_VOICEVOL:
450
case _GUS_VOICEVOL2:
451
/* not supported yet */
452
return;
453
454
case _GUS_RAMPRANGE:
455
case _GUS_RAMPRATE:
456
case _GUS_RAMPMODE:
457
case _GUS_RAMPON:
458
case _GUS_RAMPOFF:
459
/* volume ramping not supported */
460
return;
461
462
case _GUS_VOLUME_SCALE:
463
return;
464
465
case _GUS_VOICE_POS:
466
#ifdef SNDRV_EMUX_USE_RAW_EFFECT
467
snd_emux_send_effect(port, chan, EMUX_FX_SAMPLE_START,
468
(short)(plong & 0x7fff),
469
EMUX_FX_FLAG_SET);
470
snd_emux_send_effect(port, chan, EMUX_FX_COARSE_SAMPLE_START,
471
(plong >> 15) & 0xffff,
472
EMUX_FX_FLAG_SET);
473
#endif
474
return;
475
}
476
}
477
478
479
/*
480
* send an event to midi emulation
481
*/
482
static void
483
fake_event(struct snd_emux *emu, struct snd_emux_port *port, int ch, int param, int val, int atomic, int hop)
484
{
485
struct snd_seq_event ev;
486
memset(&ev, 0, sizeof(ev));
487
ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
488
ev.data.control.channel = ch;
489
ev.data.control.param = param;
490
ev.data.control.value = val;
491
snd_emux_event_input(&ev, 0, port, atomic, hop);
492
}
493
494