162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Interface for OSS sequencer emulation 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1999 Takashi Iwai <tiwai@suse.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Changes 862306a36Sopenharmony_ci * 19990227 Steve Ratcliffe Made separate file and merged in latest 962306a36Sopenharmony_ci * midi emulation. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/export.h> 1462306a36Sopenharmony_ci#include <linux/uaccess.h> 1562306a36Sopenharmony_ci#include <sound/core.h> 1662306a36Sopenharmony_ci#include "emux_voice.h" 1762306a36Sopenharmony_ci#include <sound/asoundef.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure); 2062306a36Sopenharmony_cistatic int snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg); 2162306a36Sopenharmony_cistatic int snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, 2262306a36Sopenharmony_ci unsigned long ioarg); 2362306a36Sopenharmony_cistatic int snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, 2462306a36Sopenharmony_ci const char __user *buf, int offs, int count); 2562306a36Sopenharmony_cistatic int snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg); 2662306a36Sopenharmony_cistatic int snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, 2762306a36Sopenharmony_ci void *private, int atomic, int hop); 2862306a36Sopenharmony_cistatic void reset_port_mode(struct snd_emux_port *port, int midi_mode); 2962306a36Sopenharmony_cistatic void emuspec_control(struct snd_emux *emu, struct snd_emux_port *port, 3062306a36Sopenharmony_ci int cmd, unsigned char *event, int atomic, int hop); 3162306a36Sopenharmony_cistatic void gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, 3262306a36Sopenharmony_ci int cmd, unsigned char *event, int atomic, int hop); 3362306a36Sopenharmony_cistatic void fake_event(struct snd_emux *emu, struct snd_emux_port *port, 3462306a36Sopenharmony_ci int ch, int param, int val, int atomic, int hop); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* operators */ 3762306a36Sopenharmony_cistatic const struct snd_seq_oss_callback oss_callback = { 3862306a36Sopenharmony_ci .owner = THIS_MODULE, 3962306a36Sopenharmony_ci .open = snd_emux_open_seq_oss, 4062306a36Sopenharmony_ci .close = snd_emux_close_seq_oss, 4162306a36Sopenharmony_ci .ioctl = snd_emux_ioctl_seq_oss, 4262306a36Sopenharmony_ci .load_patch = snd_emux_load_patch_seq_oss, 4362306a36Sopenharmony_ci .reset = snd_emux_reset_seq_oss, 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * register OSS synth 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_civoid 5262306a36Sopenharmony_cisnd_emux_init_seq_oss(struct snd_emux *emu) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct snd_seq_oss_reg *arg; 5562306a36Sopenharmony_ci struct snd_seq_device *dev; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* using device#1 here for avoiding conflicts with OPL3 */ 5862306a36Sopenharmony_ci if (snd_seq_device_new(emu->card, 1, SNDRV_SEQ_DEV_ID_OSS, 5962306a36Sopenharmony_ci sizeof(struct snd_seq_oss_reg), &dev) < 0) 6062306a36Sopenharmony_ci return; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci emu->oss_synth = dev; 6362306a36Sopenharmony_ci strcpy(dev->name, emu->name); 6462306a36Sopenharmony_ci arg = SNDRV_SEQ_DEVICE_ARGPTR(dev); 6562306a36Sopenharmony_ci arg->type = SYNTH_TYPE_SAMPLE; 6662306a36Sopenharmony_ci arg->subtype = SAMPLE_TYPE_AWE32; 6762306a36Sopenharmony_ci arg->nvoices = emu->max_voices; 6862306a36Sopenharmony_ci arg->oper = oss_callback; 6962306a36Sopenharmony_ci arg->private_data = emu; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* register to OSS synth table */ 7262306a36Sopenharmony_ci snd_device_register(emu->card, dev); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* 7762306a36Sopenharmony_ci * unregister 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_civoid 8062306a36Sopenharmony_cisnd_emux_detach_seq_oss(struct snd_emux *emu) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci if (emu->oss_synth) { 8362306a36Sopenharmony_ci snd_device_free(emu->card, emu->oss_synth); 8462306a36Sopenharmony_ci emu->oss_synth = NULL; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* use port number as a unique soundfont client number */ 9062306a36Sopenharmony_ci#define SF_CLIENT_NO(p) ((p) + 0x1000) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* 9362306a36Sopenharmony_ci * open port for OSS sequencer 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_cistatic int 9662306a36Sopenharmony_cisnd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct snd_emux *emu; 9962306a36Sopenharmony_ci struct snd_emux_port *p; 10062306a36Sopenharmony_ci struct snd_seq_port_callback callback; 10162306a36Sopenharmony_ci char tmpname[64]; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci emu = closure; 10462306a36Sopenharmony_ci if (snd_BUG_ON(!arg || !emu)) 10562306a36Sopenharmony_ci return -ENXIO; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (!snd_emux_inc_count(emu)) 10862306a36Sopenharmony_ci return -EFAULT; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci memset(&callback, 0, sizeof(callback)); 11162306a36Sopenharmony_ci callback.owner = THIS_MODULE; 11262306a36Sopenharmony_ci callback.event_input = snd_emux_event_oss_input; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci sprintf(tmpname, "%s OSS Port", emu->name); 11562306a36Sopenharmony_ci p = snd_emux_create_port(emu, tmpname, 32, 11662306a36Sopenharmony_ci 1, &callback); 11762306a36Sopenharmony_ci if (p == NULL) { 11862306a36Sopenharmony_ci snd_printk(KERN_ERR "can't create port\n"); 11962306a36Sopenharmony_ci snd_emux_dec_count(emu); 12062306a36Sopenharmony_ci return -ENOMEM; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* fill the argument data */ 12462306a36Sopenharmony_ci arg->private_data = p; 12562306a36Sopenharmony_ci arg->addr.client = p->chset.client; 12662306a36Sopenharmony_ci arg->addr.port = p->chset.port; 12762306a36Sopenharmony_ci p->oss_arg = arg; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci reset_port_mode(p, arg->seq_mode); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci snd_emux_reset_port(p); 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci#define DEFAULT_DRUM_FLAGS ((1<<9) | (1<<25)) 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* 13962306a36Sopenharmony_ci * reset port mode 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_cistatic void 14262306a36Sopenharmony_cireset_port_mode(struct snd_emux_port *port, int midi_mode) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci if (midi_mode) { 14562306a36Sopenharmony_ci port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_MIDI; 14662306a36Sopenharmony_ci port->drum_flags = DEFAULT_DRUM_FLAGS; 14762306a36Sopenharmony_ci port->volume_atten = 0; 14862306a36Sopenharmony_ci port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_KEYPRESS; 14962306a36Sopenharmony_ci } else { 15062306a36Sopenharmony_ci port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_SYNTH; 15162306a36Sopenharmony_ci port->drum_flags = 0; 15262306a36Sopenharmony_ci port->volume_atten = 32; 15362306a36Sopenharmony_ci port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/* 15962306a36Sopenharmony_ci * close port 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_cistatic int 16262306a36Sopenharmony_cisnd_emux_close_seq_oss(struct snd_seq_oss_arg *arg) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct snd_emux *emu; 16562306a36Sopenharmony_ci struct snd_emux_port *p; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (snd_BUG_ON(!arg)) 16862306a36Sopenharmony_ci return -ENXIO; 16962306a36Sopenharmony_ci p = arg->private_data; 17062306a36Sopenharmony_ci if (snd_BUG_ON(!p)) 17162306a36Sopenharmony_ci return -ENXIO; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci emu = p->emu; 17462306a36Sopenharmony_ci if (snd_BUG_ON(!emu)) 17562306a36Sopenharmony_ci return -ENXIO; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci snd_emux_sounds_off_all(p); 17862306a36Sopenharmony_ci snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port)); 17962306a36Sopenharmony_ci snd_seq_event_port_detach(p->chset.client, p->chset.port); 18062306a36Sopenharmony_ci snd_emux_dec_count(emu); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* 18762306a36Sopenharmony_ci * load patch 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_cistatic int 19062306a36Sopenharmony_cisnd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, 19162306a36Sopenharmony_ci const char __user *buf, int offs, int count) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct snd_emux *emu; 19462306a36Sopenharmony_ci struct snd_emux_port *p; 19562306a36Sopenharmony_ci int rc; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (snd_BUG_ON(!arg)) 19862306a36Sopenharmony_ci return -ENXIO; 19962306a36Sopenharmony_ci p = arg->private_data; 20062306a36Sopenharmony_ci if (snd_BUG_ON(!p)) 20162306a36Sopenharmony_ci return -ENXIO; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci emu = p->emu; 20462306a36Sopenharmony_ci if (snd_BUG_ON(!emu)) 20562306a36Sopenharmony_ci return -ENXIO; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (format == GUS_PATCH) 20862306a36Sopenharmony_ci rc = snd_soundfont_load_guspatch(emu->sflist, buf, count, 20962306a36Sopenharmony_ci SF_CLIENT_NO(p->chset.port)); 21062306a36Sopenharmony_ci else if (format == SNDRV_OSS_SOUNDFONT_PATCH) { 21162306a36Sopenharmony_ci struct soundfont_patch_info patch; 21262306a36Sopenharmony_ci if (count < (int)sizeof(patch)) 21362306a36Sopenharmony_ci return -EINVAL; 21462306a36Sopenharmony_ci if (copy_from_user(&patch, buf, sizeof(patch))) 21562306a36Sopenharmony_ci return -EFAULT; 21662306a36Sopenharmony_ci if (patch.type >= SNDRV_SFNT_LOAD_INFO && 21762306a36Sopenharmony_ci patch.type <= SNDRV_SFNT_PROBE_DATA) 21862306a36Sopenharmony_ci rc = snd_soundfont_load(emu->sflist, buf, count, SF_CLIENT_NO(p->chset.port)); 21962306a36Sopenharmony_ci else { 22062306a36Sopenharmony_ci if (emu->ops.load_fx) 22162306a36Sopenharmony_ci rc = emu->ops.load_fx(emu, patch.type, patch.optarg, buf, count); 22262306a36Sopenharmony_ci else 22362306a36Sopenharmony_ci rc = -EINVAL; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } else 22662306a36Sopenharmony_ci rc = 0; 22762306a36Sopenharmony_ci return rc; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* 23262306a36Sopenharmony_ci * ioctl 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_cistatic int 23562306a36Sopenharmony_cisnd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned long ioarg) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct snd_emux_port *p; 23862306a36Sopenharmony_ci struct snd_emux *emu; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (snd_BUG_ON(!arg)) 24162306a36Sopenharmony_ci return -ENXIO; 24262306a36Sopenharmony_ci p = arg->private_data; 24362306a36Sopenharmony_ci if (snd_BUG_ON(!p)) 24462306a36Sopenharmony_ci return -ENXIO; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci emu = p->emu; 24762306a36Sopenharmony_ci if (snd_BUG_ON(!emu)) 24862306a36Sopenharmony_ci return -ENXIO; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci switch (cmd) { 25162306a36Sopenharmony_ci case SNDCTL_SEQ_RESETSAMPLES: 25262306a36Sopenharmony_ci snd_soundfont_remove_samples(emu->sflist); 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci case SNDCTL_SYNTH_MEMAVL: 25662306a36Sopenharmony_ci if (emu->memhdr) 25762306a36Sopenharmony_ci return snd_util_mem_avail(emu->memhdr); 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/* 26662306a36Sopenharmony_ci * reset device 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_cistatic int 26962306a36Sopenharmony_cisnd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct snd_emux_port *p; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (snd_BUG_ON(!arg)) 27462306a36Sopenharmony_ci return -ENXIO; 27562306a36Sopenharmony_ci p = arg->private_data; 27662306a36Sopenharmony_ci if (snd_BUG_ON(!p)) 27762306a36Sopenharmony_ci return -ENXIO; 27862306a36Sopenharmony_ci snd_emux_reset_port(p); 27962306a36Sopenharmony_ci return 0; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* 28462306a36Sopenharmony_ci * receive raw events: only SEQ_PRIVATE is accepted. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_cistatic int 28762306a36Sopenharmony_cisnd_emux_event_oss_input(struct snd_seq_event *ev, int direct, void *private_data, 28862306a36Sopenharmony_ci int atomic, int hop) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct snd_emux *emu; 29162306a36Sopenharmony_ci struct snd_emux_port *p; 29262306a36Sopenharmony_ci unsigned char cmd, *data; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci p = private_data; 29562306a36Sopenharmony_ci if (snd_BUG_ON(!p)) 29662306a36Sopenharmony_ci return -EINVAL; 29762306a36Sopenharmony_ci emu = p->emu; 29862306a36Sopenharmony_ci if (snd_BUG_ON(!emu)) 29962306a36Sopenharmony_ci return -EINVAL; 30062306a36Sopenharmony_ci if (ev->type != SNDRV_SEQ_EVENT_OSS) 30162306a36Sopenharmony_ci return snd_emux_event_input(ev, direct, private_data, atomic, hop); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci data = ev->data.raw8.d; 30462306a36Sopenharmony_ci /* only SEQ_PRIVATE is accepted */ 30562306a36Sopenharmony_ci if (data[0] != 0xfe) 30662306a36Sopenharmony_ci return 0; 30762306a36Sopenharmony_ci cmd = data[2] & _EMUX_OSS_MODE_VALUE_MASK; 30862306a36Sopenharmony_ci if (data[2] & _EMUX_OSS_MODE_FLAG) 30962306a36Sopenharmony_ci emuspec_control(emu, p, cmd, data, atomic, hop); 31062306a36Sopenharmony_ci else 31162306a36Sopenharmony_ci gusspec_control(emu, p, cmd, data, atomic, hop); 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/* 31762306a36Sopenharmony_ci * OSS/AWE driver specific h/w controls 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_cistatic void 32062306a36Sopenharmony_ciemuspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, 32162306a36Sopenharmony_ci unsigned char *event, int atomic, int hop) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci int voice; 32462306a36Sopenharmony_ci unsigned short p1; 32562306a36Sopenharmony_ci short p2; 32662306a36Sopenharmony_ci int i; 32762306a36Sopenharmony_ci struct snd_midi_channel *chan; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci voice = event[3]; 33062306a36Sopenharmony_ci if (voice < 0 || voice >= port->chset.max_channels) 33162306a36Sopenharmony_ci chan = NULL; 33262306a36Sopenharmony_ci else 33362306a36Sopenharmony_ci chan = &port->chset.channels[voice]; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci p1 = *(unsigned short *) &event[4]; 33662306a36Sopenharmony_ci p2 = *(short *) &event[6]; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci switch (cmd) { 33962306a36Sopenharmony_ci#if 0 /* don't do this atomically */ 34062306a36Sopenharmony_ci case _EMUX_OSS_REMOVE_LAST_SAMPLES: 34162306a36Sopenharmony_ci snd_soundfont_remove_unlocked(emu->sflist); 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci#endif 34462306a36Sopenharmony_ci case _EMUX_OSS_SEND_EFFECT: 34562306a36Sopenharmony_ci if (chan) 34662306a36Sopenharmony_ci snd_emux_send_effect_oss(port, chan, p1, p2); 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci case _EMUX_OSS_TERMINATE_ALL: 35062306a36Sopenharmony_ci snd_emux_terminate_all(emu); 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci case _EMUX_OSS_TERMINATE_CHANNEL: 35462306a36Sopenharmony_ci /*snd_emux_mute_channel(emu, chan);*/ 35562306a36Sopenharmony_ci break; 35662306a36Sopenharmony_ci case _EMUX_OSS_RESET_CHANNEL: 35762306a36Sopenharmony_ci /*snd_emux_channel_init(chset, chan);*/ 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci case _EMUX_OSS_RELEASE_ALL: 36162306a36Sopenharmony_ci fake_event(emu, port, voice, MIDI_CTL_ALL_NOTES_OFF, 0, atomic, hop); 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci case _EMUX_OSS_NOTEOFF_ALL: 36462306a36Sopenharmony_ci fake_event(emu, port, voice, MIDI_CTL_ALL_SOUNDS_OFF, 0, atomic, hop); 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci case _EMUX_OSS_INITIAL_VOLUME: 36862306a36Sopenharmony_ci if (p2) { 36962306a36Sopenharmony_ci port->volume_atten = (short)p1; 37062306a36Sopenharmony_ci snd_emux_update_port(port, SNDRV_EMUX_UPDATE_VOLUME); 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci case _EMUX_OSS_CHN_PRESSURE: 37562306a36Sopenharmony_ci if (chan) { 37662306a36Sopenharmony_ci chan->midi_pressure = p1; 37762306a36Sopenharmony_ci snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_FMMOD|SNDRV_EMUX_UPDATE_FM2FRQ2); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci case _EMUX_OSS_CHANNEL_MODE: 38262306a36Sopenharmony_ci reset_port_mode(port, p1); 38362306a36Sopenharmony_ci snd_emux_reset_port(port); 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci case _EMUX_OSS_DRUM_CHANNELS: 38762306a36Sopenharmony_ci port->drum_flags = *(unsigned int*)&event[4]; 38862306a36Sopenharmony_ci for (i = 0; i < port->chset.max_channels; i++) { 38962306a36Sopenharmony_ci chan = &port->chset.channels[i]; 39062306a36Sopenharmony_ci chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci case _EMUX_OSS_MISC_MODE: 39562306a36Sopenharmony_ci if (p1 < EMUX_MD_END) 39662306a36Sopenharmony_ci port->ctrls[p1] = p2; 39762306a36Sopenharmony_ci break; 39862306a36Sopenharmony_ci case _EMUX_OSS_DEBUG_MODE: 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci default: 40262306a36Sopenharmony_ci if (emu->ops.oss_ioctl) 40362306a36Sopenharmony_ci emu->ops.oss_ioctl(emu, cmd, p1, p2); 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/* 40962306a36Sopenharmony_ci * GUS specific h/w controls 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci#include <linux/ultrasound.h> 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic void 41562306a36Sopenharmony_cigusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, 41662306a36Sopenharmony_ci unsigned char *event, int atomic, int hop) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci int voice; 41962306a36Sopenharmony_ci unsigned short p1; 42062306a36Sopenharmony_ci int plong; 42162306a36Sopenharmony_ci struct snd_midi_channel *chan; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (port->port_mode != SNDRV_EMUX_PORT_MODE_OSS_SYNTH) 42462306a36Sopenharmony_ci return; 42562306a36Sopenharmony_ci if (cmd == _GUS_NUMVOICES) 42662306a36Sopenharmony_ci return; 42762306a36Sopenharmony_ci voice = event[3]; 42862306a36Sopenharmony_ci if (voice < 0 || voice >= port->chset.max_channels) 42962306a36Sopenharmony_ci return; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci chan = &port->chset.channels[voice]; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci p1 = *(unsigned short *) &event[4]; 43462306a36Sopenharmony_ci plong = *(int*) &event[4]; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci switch (cmd) { 43762306a36Sopenharmony_ci case _GUS_VOICESAMPLE: 43862306a36Sopenharmony_ci chan->midi_program = p1; 43962306a36Sopenharmony_ci return; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci case _GUS_VOICEBALA: 44262306a36Sopenharmony_ci /* 0 to 15 --> 0 to 127 */ 44362306a36Sopenharmony_ci chan->control[MIDI_CTL_MSB_PAN] = (int)p1 << 3; 44462306a36Sopenharmony_ci snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PAN); 44562306a36Sopenharmony_ci return; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci case _GUS_VOICEVOL: 44862306a36Sopenharmony_ci case _GUS_VOICEVOL2: 44962306a36Sopenharmony_ci /* not supported yet */ 45062306a36Sopenharmony_ci return; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci case _GUS_RAMPRANGE: 45362306a36Sopenharmony_ci case _GUS_RAMPRATE: 45462306a36Sopenharmony_ci case _GUS_RAMPMODE: 45562306a36Sopenharmony_ci case _GUS_RAMPON: 45662306a36Sopenharmony_ci case _GUS_RAMPOFF: 45762306a36Sopenharmony_ci /* volume ramping not supported */ 45862306a36Sopenharmony_ci return; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci case _GUS_VOLUME_SCALE: 46162306a36Sopenharmony_ci return; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci case _GUS_VOICE_POS: 46462306a36Sopenharmony_ci#ifdef SNDRV_EMUX_USE_RAW_EFFECT 46562306a36Sopenharmony_ci snd_emux_send_effect(port, chan, EMUX_FX_SAMPLE_START, 46662306a36Sopenharmony_ci (short)(plong & 0x7fff), 46762306a36Sopenharmony_ci EMUX_FX_FLAG_SET); 46862306a36Sopenharmony_ci snd_emux_send_effect(port, chan, EMUX_FX_COARSE_SAMPLE_START, 46962306a36Sopenharmony_ci (plong >> 15) & 0xffff, 47062306a36Sopenharmony_ci EMUX_FX_FLAG_SET); 47162306a36Sopenharmony_ci#endif 47262306a36Sopenharmony_ci return; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/* 47862306a36Sopenharmony_ci * send an event to midi emulation 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_cistatic void 48162306a36Sopenharmony_cifake_event(struct snd_emux *emu, struct snd_emux_port *port, int ch, int param, int val, int atomic, int hop) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct snd_seq_event ev; 48462306a36Sopenharmony_ci memset(&ev, 0, sizeof(ev)); 48562306a36Sopenharmony_ci ev.type = SNDRV_SEQ_EVENT_CONTROLLER; 48662306a36Sopenharmony_ci ev.data.control.channel = ch; 48762306a36Sopenharmony_ci ev.data.control.param = param; 48862306a36Sopenharmony_ci ev.data.control.value = val; 48962306a36Sopenharmony_ci snd_emux_event_input(&ev, 0, port, atomic, hop); 49062306a36Sopenharmony_ci} 491