brintos

brintos / linux-shallow public Read only

0
0
Text · 8.2 KiB · 9daced0 Raw
403 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Midi Sequencer interface routines.4 *5 *  Copyright (C) 1999 Steve Ratcliffe6 *  Copyright (c) 1999-2000 Takashi Iwai <tiwai@suse.de>7 */8 9#include "emux_voice.h"10#include <linux/slab.h>11#include <linux/module.h>12 13/* Prototypes for static functions */14static void free_port(void *private);15static void snd_emux_init_port(struct snd_emux_port *p);16static int snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info);17static int snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info);18 19/*20 * MIDI emulation operators21 */22static const struct snd_midi_op emux_ops = {23	.note_on = snd_emux_note_on,24	.note_off = snd_emux_note_off,25	.key_press = snd_emux_key_press,26	.note_terminate = snd_emux_terminate_note,27	.control = snd_emux_control,28	.nrpn = snd_emux_nrpn,29	.sysex = snd_emux_sysex,30};31 32 33/*34 * number of MIDI channels35 */36#define MIDI_CHANNELS		1637 38/*39 * type flags for MIDI sequencer port40 */41#define DEFAULT_MIDI_TYPE	(SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |\42				 SNDRV_SEQ_PORT_TYPE_MIDI_GM |\43				 SNDRV_SEQ_PORT_TYPE_MIDI_GS |\44				 SNDRV_SEQ_PORT_TYPE_MIDI_XG |\45				 SNDRV_SEQ_PORT_TYPE_HARDWARE |\46				 SNDRV_SEQ_PORT_TYPE_SYNTHESIZER)47 48/*49 * Initialise the EMUX Synth by creating a client and registering50 * a series of ports.51 * Each of the ports will contain the 16 midi channels.  Applications52 * can connect to these ports to play midi data.53 */54int55snd_emux_init_seq(struct snd_emux *emu, struct snd_card *card, int index)56{57	int  i;58	struct snd_seq_port_callback pinfo;59	char tmpname[64];60 61	emu->client = snd_seq_create_kernel_client(card, index,62						   "%s WaveTable", emu->name);63	if (emu->client < 0) {64		dev_err(card->dev, "can't create client\n");65		return -ENODEV;66	}67 68	if (emu->num_ports <= 0) {69		dev_warn(card->dev, "seqports must be greater than zero\n");70		emu->num_ports = 1;71	} else if (emu->num_ports > SNDRV_EMUX_MAX_PORTS) {72		dev_warn(card->dev,73			 "too many ports. limited max. ports %d\n",74			 SNDRV_EMUX_MAX_PORTS);75		emu->num_ports = SNDRV_EMUX_MAX_PORTS;76	}77 78	memset(&pinfo, 0, sizeof(pinfo));79	pinfo.owner = THIS_MODULE;80	pinfo.use = snd_emux_use;81	pinfo.unuse = snd_emux_unuse;82	pinfo.event_input = snd_emux_event_input;83 84	for (i = 0; i < emu->num_ports; i++) {85		struct snd_emux_port *p;86 87		sprintf(tmpname, "%s Port %d", emu->name, i);88		p = snd_emux_create_port(emu, tmpname, MIDI_CHANNELS,89					 0, &pinfo);90		if (!p) {91			dev_err(card->dev, "can't create port\n");92			return -ENOMEM;93		}94 95		p->port_mode =  SNDRV_EMUX_PORT_MODE_MIDI;96		snd_emux_init_port(p);97		emu->ports[i] = p->chset.port;98		emu->portptrs[i] = p;99	}100 101	return 0;102}103 104 105/*106 * Detach from the ports that were set up for this synthesizer and107 * destroy the kernel client.108 */109void110snd_emux_detach_seq(struct snd_emux *emu)111{112	if (emu->voices)113		snd_emux_terminate_all(emu);114		115	if (emu->client >= 0) {116		snd_seq_delete_kernel_client(emu->client);117		emu->client = -1;118	}119}120 121 122/*123 * create a sequencer port and channel_set124 */125 126struct snd_emux_port *127snd_emux_create_port(struct snd_emux *emu, char *name,128		     int max_channels, int oss_port,129		     struct snd_seq_port_callback *callback)130{131	struct snd_emux_port *p;132	int i, type, cap;133 134	/* Allocate structures for this channel */135	p = kzalloc(sizeof(*p), GFP_KERNEL);136	if (!p)137		return NULL;138 139	p->chset.channels = kcalloc(max_channels, sizeof(*p->chset.channels),140				    GFP_KERNEL);141	if (!p->chset.channels) {142		kfree(p);143		return NULL;144	}145	for (i = 0; i < max_channels; i++)146		p->chset.channels[i].number = i;147	p->chset.private_data = p;148	p->chset.max_channels = max_channels;149	p->emu = emu;150	p->chset.client = emu->client;151#ifdef SNDRV_EMUX_USE_RAW_EFFECT152	snd_emux_create_effect(p);153#endif154	callback->private_free = free_port;155	callback->private_data = p;156 157	cap = SNDRV_SEQ_PORT_CAP_WRITE;158	if (oss_port) {159		type = SNDRV_SEQ_PORT_TYPE_SPECIFIC;160	} else {161		type = DEFAULT_MIDI_TYPE;162		cap |= SNDRV_SEQ_PORT_CAP_SUBS_WRITE;163	}164 165	p->chset.port = snd_seq_event_port_attach(emu->client, callback,166						  cap, type, max_channels,167						  emu->max_voices, name);168 169	return p;170}171 172 173/*174 * release memory block for port175 */176static void177free_port(void *private_data)178{179	struct snd_emux_port *p;180 181	p = private_data;182	if (p) {183#ifdef SNDRV_EMUX_USE_RAW_EFFECT184		snd_emux_delete_effect(p);185#endif186		kfree(p->chset.channels);187		kfree(p);188	}189}190 191 192#define DEFAULT_DRUM_FLAGS	(1<<9)193 194/*195 * initialize the port specific parameters196 */197static void198snd_emux_init_port(struct snd_emux_port *p)199{200	p->drum_flags = DEFAULT_DRUM_FLAGS;201	p->volume_atten = 0;202 203	snd_emux_reset_port(p);204}205 206 207/*208 * reset port209 */210void211snd_emux_reset_port(struct snd_emux_port *port)212{213	int i;214 215	/* stop all sounds */216	snd_emux_sounds_off_all(port);217 218	snd_midi_channel_set_clear(&port->chset);219 220#ifdef SNDRV_EMUX_USE_RAW_EFFECT221	snd_emux_clear_effect(port);222#endif223 224	/* set port specific control parameters */225	port->ctrls[EMUX_MD_DEF_BANK] = 0;226	port->ctrls[EMUX_MD_DEF_DRUM] = 0;227	port->ctrls[EMUX_MD_REALTIME_PAN] = 1;228 229	for (i = 0; i < port->chset.max_channels; i++) {230		struct snd_midi_channel *chan = port->chset.channels + i;231		chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0;232	}233}234 235 236/*237 * input sequencer event238 */239int240snd_emux_event_input(struct snd_seq_event *ev, int direct, void *private_data,241		     int atomic, int hop)242{243	struct snd_emux_port *port;244 245	port = private_data;246	if (snd_BUG_ON(!port || !ev))247		return -EINVAL;248 249	snd_midi_process_event(&emux_ops, ev, &port->chset);250 251	return 0;252}253 254 255/*256 * increment usage count257 */258static int259__snd_emux_inc_count(struct snd_emux *emu)260{261	emu->used++;262	if (!try_module_get(emu->ops.owner))263		goto __error;264	if (!try_module_get(emu->card->module)) {265		module_put(emu->ops.owner);266	      __error:267		emu->used--;268		return 0;269	}270	return 1;271}272 273int snd_emux_inc_count(struct snd_emux *emu)274{275	int ret;276 277	mutex_lock(&emu->register_mutex);278	ret = __snd_emux_inc_count(emu);279	mutex_unlock(&emu->register_mutex);280	return ret;281}282 283/*284 * decrease usage count285 */286static void287__snd_emux_dec_count(struct snd_emux *emu)288{289	module_put(emu->card->module);290	emu->used--;291	if (emu->used <= 0)292		snd_emux_terminate_all(emu);293	module_put(emu->ops.owner);294}295 296void snd_emux_dec_count(struct snd_emux *emu)297{298	mutex_lock(&emu->register_mutex);299	__snd_emux_dec_count(emu);300	mutex_unlock(&emu->register_mutex);301}302 303/*304 * Routine that is called upon a first use of a particular port305 */306static int307snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info)308{309	struct snd_emux_port *p;310	struct snd_emux *emu;311 312	p = private_data;313	if (snd_BUG_ON(!p))314		return -EINVAL;315	emu = p->emu;316	if (snd_BUG_ON(!emu))317		return -EINVAL;318 319	mutex_lock(&emu->register_mutex);320	snd_emux_init_port(p);321	__snd_emux_inc_count(emu);322	mutex_unlock(&emu->register_mutex);323	return 0;324}325 326/*327 * Routine that is called upon the last unuse() of a particular port.328 */329static int330snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info)331{332	struct snd_emux_port *p;333	struct snd_emux *emu;334 335	p = private_data;336	if (snd_BUG_ON(!p))337		return -EINVAL;338	emu = p->emu;339	if (snd_BUG_ON(!emu))340		return -EINVAL;341 342	mutex_lock(&emu->register_mutex);343	snd_emux_sounds_off_all(p);344	__snd_emux_dec_count(emu);345	mutex_unlock(&emu->register_mutex);346	return 0;347}348 349 350/*351 * attach virtual rawmidi devices352 */353int snd_emux_init_virmidi(struct snd_emux *emu, struct snd_card *card)354{355	int i;356 357	emu->vmidi = NULL;358	if (emu->midi_ports <= 0)359		return 0;360 361	emu->vmidi = kcalloc(emu->midi_ports, sizeof(*emu->vmidi), GFP_KERNEL);362	if (!emu->vmidi)363		return -ENOMEM;364 365	for (i = 0; i < emu->midi_ports; i++) {366		struct snd_rawmidi *rmidi;367		struct snd_virmidi_dev *rdev;368		if (snd_virmidi_new(card, emu->midi_devidx + i, &rmidi) < 0)369			goto __error;370		rdev = rmidi->private_data;371		sprintf(rmidi->name, "%s Synth MIDI", emu->name);372		rdev->seq_mode = SNDRV_VIRMIDI_SEQ_ATTACH;373		rdev->client = emu->client;374		rdev->port = emu->ports[i];375		if (snd_device_register(card, rmidi) < 0) {376			snd_device_free(card, rmidi);377			goto __error;378		}379		emu->vmidi[i] = rmidi;380	}381	return 0;382 383__error:384	snd_emux_delete_virmidi(emu);385	return -ENOMEM;386}387 388int snd_emux_delete_virmidi(struct snd_emux *emu)389{390	int i;391 392	if (!emu->vmidi)393		return 0;394 395	for (i = 0; i < emu->midi_ports; i++) {396		if (emu->vmidi[i])397			snd_device_free(emu->card, emu->vmidi[i]);398	}399	kfree(emu->vmidi);400	emu->vmidi = NULL;401	return 0;402}403