File Index
Files and directories
Sign in
FILE

seq_oss_synth.c

File preview with syntax highlighting.

linux-6.19.14/sound/core/seq/oss/seq_oss_synth.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * OSS compatible sequencer driver
  4 *
  5 * synth device handlers
  6 *
  7 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
  8 */
  9
 10#include "seq_oss_synth.h"
 11#include "seq_oss_midi.h"
 12#include "../seq_lock.h"
 13#include <linux/init.h>
 14#include <linux/module.h>
 15#include <linux/slab.h>
 16#include <linux/nospec.h>
 17
 18/*
 19 * constants
 20 */
 21#define SNDRV_SEQ_OSS_MAX_SYNTH_NAME	30
 22#define MAX_SYSEX_BUFLEN		128
 23
 24
 25/*
 26 * definition of synth info records
 27 */
 28
 29/* synth info */
 30struct seq_oss_synth {
 31	int seq_device;
 32
 33	/* for synth_info */
 34	int synth_type;
 35	int synth_subtype;
 36	int nr_voices;
 37
 38	char name[SNDRV_SEQ_OSS_MAX_SYNTH_NAME];
 39	struct snd_seq_oss_callback oper;
 40
 41	int opened;
 42
 43	void *private_data;
 44	snd_use_lock_t use_lock;
 45};
 46
 47DEFINE_FREE(seq_oss_synth, struct seq_oss_synth *, if (!IS_ERR_OR_NULL(_T)) snd_use_lock_free(&(_T)->use_lock))
 48
 49/*
 50 * device table
 51 */
 52static int max_synth_devs;
 53static struct seq_oss_synth *synth_devs[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS];
 54static struct seq_oss_synth midi_synth_dev = {
 55	.seq_device = -1,
 56	.synth_type = SYNTH_TYPE_MIDI,
 57	.synth_subtype = 0,
 58	.nr_voices = 16,
 59	.name = "MIDI",
 60};
 61
 62static DEFINE_SPINLOCK(register_lock);
 63
 64/*
 65 * prototypes
 66 */
 67static struct seq_oss_synth *get_synthdev(struct seq_oss_devinfo *dp, int dev);
 68static void reset_channels(struct seq_oss_synthinfo *info);
 69
 70/*
 71 * global initialization
 72 */
 73void __init
 74snd_seq_oss_synth_init(void)
 75{
 76	snd_use_lock_init(&midi_synth_dev.use_lock);
 77}
 78
 79/*
 80 * registration of the synth device
 81 */
 82int
 83snd_seq_oss_synth_probe(struct device *_dev)
 84{
 85	struct snd_seq_device *dev = to_seq_dev(_dev);
 86	int i;
 87	struct seq_oss_synth *rec;
 88	struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
 89
 90	rec = kzalloc(sizeof(*rec), GFP_KERNEL);
 91	if (!rec)
 92		return -ENOMEM;
 93	rec->seq_device = -1;
 94	rec->synth_type = reg->type;
 95	rec->synth_subtype = reg->subtype;
 96	rec->nr_voices = reg->nvoices;
 97	rec->oper = reg->oper;
 98	rec->private_data = reg->private_data;
 99	rec->opened = 0;
100	snd_use_lock_init(&rec->use_lock);
101
102	/* copy and truncate the name of synth device */
103	strscpy(rec->name, dev->name, sizeof(rec->name));
104
105	/* registration */
106	scoped_guard(spinlock_irqsave, &register_lock) {
107		for (i = 0; i < max_synth_devs; i++) {
108			if (synth_devs[i] == NULL)
109				break;
110		}
111		if (i >= max_synth_devs) {
112			if (max_synth_devs >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) {
113				pr_err("ALSA: seq_oss: no more synth slot\n");
114				kfree(rec);
115				return -ENOMEM;
116			}
117			max_synth_devs++;
118		}
119		rec->seq_device = i;
120		synth_devs[i] = rec;
121	}
122	dev->driver_data = rec;
123#ifdef SNDRV_OSS_INFO_DEV_SYNTH
124	if (i < SNDRV_CARDS)
125		snd_oss_info_register(SNDRV_OSS_INFO_DEV_SYNTH, i, rec->name);
126#endif
127	return 0;
128}
129
130
131int
132snd_seq_oss_synth_remove(struct device *_dev)
133{
134	struct snd_seq_device *dev = to_seq_dev(_dev);
135	int index;
136	struct seq_oss_synth *rec = dev->driver_data;
137
138	scoped_guard(spinlock_irqsave, &register_lock) {
139		for (index = 0; index < max_synth_devs; index++) {
140			if (synth_devs[index] == rec)
141				break;
142		}
143		if (index >= max_synth_devs) {
144			pr_err("ALSA: seq_oss: can't unregister synth\n");
145			return -EINVAL;
146		}
147		synth_devs[index] = NULL;
148		if (index == max_synth_devs - 1) {
149			for (index--; index >= 0; index--) {
150				if (synth_devs[index])
151					break;
152			}
153			max_synth_devs = index + 1;
154		}
155	}
156#ifdef SNDRV_OSS_INFO_DEV_SYNTH
157	if (rec->seq_device < SNDRV_CARDS)
158		snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_SYNTH, rec->seq_device);
159#endif
160
161	snd_use_lock_sync(&rec->use_lock);
162	kfree(rec);
163
164	return 0;
165}
166
167
168/*
169 */
170static struct seq_oss_synth *
171get_sdev(int dev)
172{
173	struct seq_oss_synth *rec;
174
175	guard(spinlock_irqsave)(&register_lock);
176	rec = synth_devs[dev];
177	if (rec)
178		snd_use_lock_use(&rec->use_lock);
179	return rec;
180}
181
182
183/*
184 * set up synth tables
185 */
186
187void
188snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
189{
190	int i;
191	struct seq_oss_synthinfo *info;
192
193	dp->max_synthdev = max_synth_devs;
194	dp->synth_opened = 0;
195	memset(dp->synths, 0, sizeof(dp->synths));
196	for (i = 0; i < dp->max_synthdev; i++) {
197		struct seq_oss_synth *rec __free(seq_oss_synth) = get_sdev(i);
198
199		if (rec == NULL)
200			continue;
201		if (rec->oper.open == NULL || rec->oper.close == NULL)
202			continue;
203		info = &dp->synths[i];
204		info->arg.app_index = dp->port;
205		info->arg.file_mode = dp->file_mode;
206		info->arg.seq_mode = dp->seq_mode;
207		if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH)
208			info->arg.event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS;
209		else
210			info->arg.event_passing = SNDRV_SEQ_OSS_PASS_EVENTS;
211		info->opened = 0;
212		if (!try_module_get(rec->oper.owner))
213			continue;
214		if (rec->oper.open(&info->arg, rec->private_data) < 0) {
215			module_put(rec->oper.owner);
216			continue;
217		}
218		info->nr_voices = rec->nr_voices;
219		if (info->nr_voices > 0) {
220			info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL);
221			if (!info->ch) {
222				rec->oper.close(&info->arg);
223				module_put(rec->oper.owner);
224				continue;
225			}
226			reset_channels(info);
227		}
228		info->opened++;
229		rec->opened++;
230		dp->synth_opened++;
231	}
232}
233
234
235/*
236 * set up synth tables for MIDI emulation - /dev/music mode only
237 */
238
239void
240snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp)
241{
242	int i;
243
244	if (dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)
245		return;
246
247	for (i = 0; i < dp->max_mididev; i++) {
248		struct seq_oss_synthinfo *info;
249		info = &dp->synths[dp->max_synthdev];
250		if (snd_seq_oss_midi_open(dp, i, dp->file_mode) < 0)
251			continue;
252		info->arg.app_index = dp->port;
253		info->arg.file_mode = dp->file_mode;
254		info->arg.seq_mode = dp->seq_mode;
255		info->arg.private_data = info;
256		info->is_midi = 1;
257		info->midi_mapped = i;
258		info->arg.event_passing = SNDRV_SEQ_OSS_PASS_EVENTS;
259		snd_seq_oss_midi_get_addr(dp, i, &info->arg.addr);
260		info->opened = 1;
261		midi_synth_dev.opened++;
262		dp->max_synthdev++;
263		if (dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)
264			break;
265	}
266}
267
268
269/*
270 * clean up synth tables
271 */
272
273void
274snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp)
275{
276	int i;
277	struct seq_oss_synthinfo *info;
278
279	if (snd_BUG_ON(dp->max_synthdev > SNDRV_SEQ_OSS_MAX_SYNTH_DEVS))
280		return;
281	for (i = 0; i < dp->max_synthdev; i++) {
282		info = &dp->synths[i];
283		if (! info->opened)
284			continue;
285		if (info->is_midi) {
286			if (midi_synth_dev.opened > 0) {
287				snd_seq_oss_midi_close(dp, info->midi_mapped);
288				midi_synth_dev.opened--;
289			}
290		} else {
291			struct seq_oss_synth *rec __free(seq_oss_synth) =
292				get_sdev(i);
293
294			if (rec == NULL)
295				continue;
296			if (rec->opened > 0) {
297				rec->oper.close(&info->arg);
298				module_put(rec->oper.owner);
299				rec->opened = 0;
300			}
301		}
302		kfree(info->ch);
303		info->ch = NULL;
304	}
305	dp->synth_opened = 0;
306	dp->max_synthdev = 0;
307}
308
309static struct seq_oss_synthinfo *
310get_synthinfo_nospec(struct seq_oss_devinfo *dp, int dev)
311{
312	if (dev < 0 || dev >= dp->max_synthdev)
313		return NULL;
314	dev = array_index_nospec(dev, SNDRV_SEQ_OSS_MAX_SYNTH_DEVS);
315	return &dp->synths[dev];
316}
317
318/*
319 * return synth device information pointer
320 */
321static struct seq_oss_synth *
322get_synthdev(struct seq_oss_devinfo *dp, int dev)
323{
324	struct seq_oss_synth *rec;
325	struct seq_oss_synthinfo *info = get_synthinfo_nospec(dp, dev);
326
327	if (!info)
328		return NULL;
329	if (!info->opened)
330		return NULL;
331	if (info->is_midi) {
332		rec = &midi_synth_dev;
333		snd_use_lock_use(&rec->use_lock);
334	} else {
335		rec = get_sdev(dev);
336		if (!rec)
337			return NULL;
338	}
339	if (! rec->opened) {
340		snd_use_lock_free(&rec->use_lock);
341		return NULL;
342	}
343	return rec;
344}
345
346
347/*
348 * reset note and velocity on each channel.
349 */
350static void
351reset_channels(struct seq_oss_synthinfo *info)
352{
353	int i;
354	if (info->ch == NULL || ! info->nr_voices)
355		return;
356	for (i = 0; i < info->nr_voices; i++) {
357		info->ch[i].note = -1;
358		info->ch[i].vel = 0;
359	}
360}
361
362
363/*
364 * reset synth device:
365 * call reset callback.  if no callback is defined, send a heartbeat
366 * event to the corresponding port.
367 */
368void
369snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev)
370{
371	struct seq_oss_synthinfo *info;
372
373	info = get_synthinfo_nospec(dp, dev);
374	if (!info || !info->opened)
375		return;
376	reset_channels(info);
377	if (info->is_midi) {
378		if (midi_synth_dev.opened <= 0)
379			return;
380		snd_seq_oss_midi_reset(dp, info->midi_mapped);
381		/* reopen the device */
382		snd_seq_oss_midi_close(dp, dev);
383		if (snd_seq_oss_midi_open(dp, info->midi_mapped,
384					  dp->file_mode) < 0) {
385			midi_synth_dev.opened--;
386			info->opened = 0;
387			kfree(info->ch);
388			info->ch = NULL;
389		}
390		return;
391	}
392
393	struct seq_oss_synth *rec __free(seq_oss_synth) =
394		get_sdev(dev);
395	if (rec == NULL)
396		return;
397	if (rec->oper.reset) {
398		rec->oper.reset(&info->arg);
399	} else {
400		struct snd_seq_event ev;
401		memset(&ev, 0, sizeof(ev));
402		snd_seq_oss_fill_addr(dp, &ev, info->arg.addr.client,
403				      info->arg.addr.port);
404		ev.type = SNDRV_SEQ_EVENT_RESET;
405		snd_seq_oss_dispatch(dp, &ev, 0, 0);
406	}
407}
408
409
410/*
411 * load a patch record:
412 * call load_patch callback function
413 */
414int
415snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt,
416			    const char __user *buf, int p, int c)
417{
418	struct seq_oss_synthinfo *info;
419
420	info = get_synthinfo_nospec(dp, dev);
421	if (!info)
422		return -ENXIO;
423
424	if (info->is_midi)
425		return 0;
426
427	struct seq_oss_synth *rec __free(seq_oss_synth) =
428		get_synthdev(dp, dev);
429	if (!rec)
430		return -ENXIO;
431
432	if (rec->oper.load_patch == NULL)
433		return -ENXIO;
434	else
435		return rec->oper.load_patch(&info->arg, fmt, buf, p, c);
436}
437
438/*
439 * check if the device is valid synth device and return the synth info
440 */
441struct seq_oss_synthinfo *
442snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, int dev)
443{
444	struct seq_oss_synth *rec __free(seq_oss_synth) =
445		get_synthdev(dp, dev);
446
447	if (rec)
448		return get_synthinfo_nospec(dp, dev);
449	return NULL;
450}
451
452
453/*
454 * receive OSS 6 byte sysex packet:
455 * the event is filled and prepared for sending immediately
456 * (i.e. sysex messages are fragmented)
457 */
458int
459snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, struct snd_seq_event *ev)
460{
461	unsigned char *p;
462	int len = 6;
463
464	p = memchr(buf, 0xff, 6);
465	if (p)
466		len = p - buf + 1;
467
468	/* copy the data to event record and send it */
469	if (snd_seq_oss_synth_addr(dp, dev, ev))
470		return -EINVAL;
471	ev->flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
472	ev->data.ext.len = len;
473	ev->data.ext.ptr = buf;
474	return 0;
475}
476
477/*
478 * fill the event source/destination addresses
479 */
480int
481snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event *ev)
482{
483	struct seq_oss_synthinfo *info = snd_seq_oss_synth_info(dp, dev);
484
485	if (!info)
486		return -EINVAL;
487	snd_seq_oss_fill_addr(dp, ev, info->arg.addr.client,
488			      info->arg.addr.port);
489	return 0;
490}
491
492
493/*
494 * OSS compatible ioctl
495 */
496int
497snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, unsigned long addr)
498{
499	struct seq_oss_synthinfo *info;
500
501	info = get_synthinfo_nospec(dp, dev);
502	if (!info || info->is_midi)
503		return -ENXIO;
504
505	struct seq_oss_synth *rec __free(seq_oss_synth) =
506		get_synthdev(dp, dev);
507	if (!rec)
508		return -ENXIO;
509	if (rec->oper.ioctl == NULL)
510		return -ENXIO;
511	else
512		return rec->oper.ioctl(&info->arg, cmd, addr);
513}
514
515
516/*
517 * send OSS raw events - SEQ_PRIVATE and SEQ_VOLUME
518 */
519int
520snd_seq_oss_synth_raw_event(struct seq_oss_devinfo *dp, int dev, unsigned char *data, struct snd_seq_event *ev)
521{
522	struct seq_oss_synthinfo *info;
523
524	info = snd_seq_oss_synth_info(dp, dev);
525	if (!info || info->is_midi)
526		return -ENXIO;
527	ev->type = SNDRV_SEQ_EVENT_OSS;
528	memcpy(ev->data.raw8.d, data, 8);
529	return snd_seq_oss_synth_addr(dp, dev, ev);
530}
531
532
533/*
534 * create OSS compatible synth_info record
535 */
536int
537snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_info *inf)
538{
539	struct seq_oss_synthinfo *info = get_synthinfo_nospec(dp, dev);
540
541	if (!info)
542		return -ENXIO;
543
544	if (info->is_midi) {
545		struct midi_info minf;
546		if (snd_seq_oss_midi_make_info(dp, info->midi_mapped, &minf))
547			return -ENXIO;
548		inf->synth_type = SYNTH_TYPE_MIDI;
549		inf->synth_subtype = 0;
550		inf->nr_voices = 16;
551		inf->device = dev;
552		strscpy(inf->name, minf.name, sizeof(inf->name));
553	} else {
554		struct seq_oss_synth *rec __free(seq_oss_synth) =
555			get_synthdev(dp, dev);
556
557		if (!rec)
558			return -ENXIO;
559		inf->synth_type = rec->synth_type;
560		inf->synth_subtype = rec->synth_subtype;
561		inf->nr_voices = rec->nr_voices;
562		inf->device = dev;
563		strscpy(inf->name, rec->name, sizeof(inf->name));
564	}
565	return 0;
566}
567
568
569#ifdef CONFIG_SND_PROC_FS
570/*
571 * proc interface
572 */
573void
574snd_seq_oss_synth_info_read(struct snd_info_buffer *buf)
575{
576	int i;
577
578	snd_iprintf(buf, "\nNumber of synth devices: %d\n", max_synth_devs);
579	for (i = 0; i < max_synth_devs; i++) {
580		snd_iprintf(buf, "\nsynth %d: ", i);
581		struct seq_oss_synth *rec __free(seq_oss_synth) =
582			get_sdev(i);
583		if (rec == NULL) {
584			snd_iprintf(buf, "*empty*\n");
585			continue;
586		}
587		snd_iprintf(buf, "[%s]\n", rec->name);
588		snd_iprintf(buf, "  type 0x%x : subtype 0x%x : voices %d\n",
589			    rec->synth_type, rec->synth_subtype,
590			    rec->nr_voices);
591		snd_iprintf(buf, "  capabilities : ioctl %s / load_patch %s\n",
592			    str_enabled_disabled((long)rec->oper.ioctl),
593			    str_enabled_disabled((long)rec->oper.load_patch));
594	}
595}
596#endif /* CONFIG_SND_PROC_FS */
~/ Read-only file preview.