18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Interface for OSS sequencer emulation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1999 Takashi Iwai <tiwai@suse.de> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Changes 88c2ecf20Sopenharmony_ci * 19990227 Steve Ratcliffe Made separate file and merged in latest 98c2ecf20Sopenharmony_ci * midi emulation. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/export.h> 148c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 158c2ecf20Sopenharmony_ci#include <sound/core.h> 168c2ecf20Sopenharmony_ci#include "emux_voice.h" 178c2ecf20Sopenharmony_ci#include <sound/asoundef.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure); 208c2ecf20Sopenharmony_cistatic int snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg); 218c2ecf20Sopenharmony_cistatic int snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, 228c2ecf20Sopenharmony_ci unsigned long ioarg); 238c2ecf20Sopenharmony_cistatic int snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, 248c2ecf20Sopenharmony_ci const char __user *buf, int offs, int count); 258c2ecf20Sopenharmony_cistatic int snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg); 268c2ecf20Sopenharmony_cistatic int snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, 278c2ecf20Sopenharmony_ci void *private, int atomic, int hop); 288c2ecf20Sopenharmony_cistatic void reset_port_mode(struct snd_emux_port *port, int midi_mode); 298c2ecf20Sopenharmony_cistatic void emuspec_control(struct snd_emux *emu, struct snd_emux_port *port, 308c2ecf20Sopenharmony_ci int cmd, unsigned char *event, int atomic, int hop); 318c2ecf20Sopenharmony_cistatic void gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, 328c2ecf20Sopenharmony_ci int cmd, unsigned char *event, int atomic, int hop); 338c2ecf20Sopenharmony_cistatic void fake_event(struct snd_emux *emu, struct snd_emux_port *port, 348c2ecf20Sopenharmony_ci int ch, int param, int val, int atomic, int hop); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* operators */ 378c2ecf20Sopenharmony_cistatic const struct snd_seq_oss_callback oss_callback = { 388c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 398c2ecf20Sopenharmony_ci .open = snd_emux_open_seq_oss, 408c2ecf20Sopenharmony_ci .close = snd_emux_close_seq_oss, 418c2ecf20Sopenharmony_ci .ioctl = snd_emux_ioctl_seq_oss, 428c2ecf20Sopenharmony_ci .load_patch = snd_emux_load_patch_seq_oss, 438c2ecf20Sopenharmony_ci .reset = snd_emux_reset_seq_oss, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * register OSS synth 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_civoid 528c2ecf20Sopenharmony_cisnd_emux_init_seq_oss(struct snd_emux *emu) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci struct snd_seq_oss_reg *arg; 558c2ecf20Sopenharmony_ci struct snd_seq_device *dev; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* using device#1 here for avoiding conflicts with OPL3 */ 588c2ecf20Sopenharmony_ci if (snd_seq_device_new(emu->card, 1, SNDRV_SEQ_DEV_ID_OSS, 598c2ecf20Sopenharmony_ci sizeof(struct snd_seq_oss_reg), &dev) < 0) 608c2ecf20Sopenharmony_ci return; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci emu->oss_synth = dev; 638c2ecf20Sopenharmony_ci strcpy(dev->name, emu->name); 648c2ecf20Sopenharmony_ci arg = SNDRV_SEQ_DEVICE_ARGPTR(dev); 658c2ecf20Sopenharmony_ci arg->type = SYNTH_TYPE_SAMPLE; 668c2ecf20Sopenharmony_ci arg->subtype = SAMPLE_TYPE_AWE32; 678c2ecf20Sopenharmony_ci arg->nvoices = emu->max_voices; 688c2ecf20Sopenharmony_ci arg->oper = oss_callback; 698c2ecf20Sopenharmony_ci arg->private_data = emu; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* register to OSS synth table */ 728c2ecf20Sopenharmony_ci snd_device_register(emu->card, dev); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* 778c2ecf20Sopenharmony_ci * unregister 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_civoid 808c2ecf20Sopenharmony_cisnd_emux_detach_seq_oss(struct snd_emux *emu) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci if (emu->oss_synth) { 838c2ecf20Sopenharmony_ci snd_device_free(emu->card, emu->oss_synth); 848c2ecf20Sopenharmony_ci emu->oss_synth = NULL; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* use port number as a unique soundfont client number */ 908c2ecf20Sopenharmony_ci#define SF_CLIENT_NO(p) ((p) + 0x1000) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* 938c2ecf20Sopenharmony_ci * open port for OSS sequencer 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_cistatic int 968c2ecf20Sopenharmony_cisnd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct snd_emux *emu; 998c2ecf20Sopenharmony_ci struct snd_emux_port *p; 1008c2ecf20Sopenharmony_ci struct snd_seq_port_callback callback; 1018c2ecf20Sopenharmony_ci char tmpname[64]; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci emu = closure; 1048c2ecf20Sopenharmony_ci if (snd_BUG_ON(!arg || !emu)) 1058c2ecf20Sopenharmony_ci return -ENXIO; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (!snd_emux_inc_count(emu)) 1088c2ecf20Sopenharmony_ci return -EFAULT; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci memset(&callback, 0, sizeof(callback)); 1118c2ecf20Sopenharmony_ci callback.owner = THIS_MODULE; 1128c2ecf20Sopenharmony_ci callback.event_input = snd_emux_event_oss_input; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci sprintf(tmpname, "%s OSS Port", emu->name); 1158c2ecf20Sopenharmony_ci p = snd_emux_create_port(emu, tmpname, 32, 1168c2ecf20Sopenharmony_ci 1, &callback); 1178c2ecf20Sopenharmony_ci if (p == NULL) { 1188c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "can't create port\n"); 1198c2ecf20Sopenharmony_ci snd_emux_dec_count(emu); 1208c2ecf20Sopenharmony_ci return -ENOMEM; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* fill the argument data */ 1248c2ecf20Sopenharmony_ci arg->private_data = p; 1258c2ecf20Sopenharmony_ci arg->addr.client = p->chset.client; 1268c2ecf20Sopenharmony_ci arg->addr.port = p->chset.port; 1278c2ecf20Sopenharmony_ci p->oss_arg = arg; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci reset_port_mode(p, arg->seq_mode); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci snd_emux_reset_port(p); 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#define DEFAULT_DRUM_FLAGS ((1<<9) | (1<<25)) 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* 1398c2ecf20Sopenharmony_ci * reset port mode 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_cistatic void 1428c2ecf20Sopenharmony_cireset_port_mode(struct snd_emux_port *port, int midi_mode) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci if (midi_mode) { 1458c2ecf20Sopenharmony_ci port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_MIDI; 1468c2ecf20Sopenharmony_ci port->drum_flags = DEFAULT_DRUM_FLAGS; 1478c2ecf20Sopenharmony_ci port->volume_atten = 0; 1488c2ecf20Sopenharmony_ci port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_KEYPRESS; 1498c2ecf20Sopenharmony_ci } else { 1508c2ecf20Sopenharmony_ci port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_SYNTH; 1518c2ecf20Sopenharmony_ci port->drum_flags = 0; 1528c2ecf20Sopenharmony_ci port->volume_atten = 32; 1538c2ecf20Sopenharmony_ci port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* 1598c2ecf20Sopenharmony_ci * close port 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_cistatic int 1628c2ecf20Sopenharmony_cisnd_emux_close_seq_oss(struct snd_seq_oss_arg *arg) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct snd_emux *emu; 1658c2ecf20Sopenharmony_ci struct snd_emux_port *p; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (snd_BUG_ON(!arg)) 1688c2ecf20Sopenharmony_ci return -ENXIO; 1698c2ecf20Sopenharmony_ci p = arg->private_data; 1708c2ecf20Sopenharmony_ci if (snd_BUG_ON(!p)) 1718c2ecf20Sopenharmony_ci return -ENXIO; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci emu = p->emu; 1748c2ecf20Sopenharmony_ci if (snd_BUG_ON(!emu)) 1758c2ecf20Sopenharmony_ci return -ENXIO; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci snd_emux_sounds_off_all(p); 1788c2ecf20Sopenharmony_ci snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port)); 1798c2ecf20Sopenharmony_ci snd_seq_event_port_detach(p->chset.client, p->chset.port); 1808c2ecf20Sopenharmony_ci snd_emux_dec_count(emu); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* 1878c2ecf20Sopenharmony_ci * load patch 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_cistatic int 1908c2ecf20Sopenharmony_cisnd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, 1918c2ecf20Sopenharmony_ci const char __user *buf, int offs, int count) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct snd_emux *emu; 1948c2ecf20Sopenharmony_ci struct snd_emux_port *p; 1958c2ecf20Sopenharmony_ci int rc; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (snd_BUG_ON(!arg)) 1988c2ecf20Sopenharmony_ci return -ENXIO; 1998c2ecf20Sopenharmony_ci p = arg->private_data; 2008c2ecf20Sopenharmony_ci if (snd_BUG_ON(!p)) 2018c2ecf20Sopenharmony_ci return -ENXIO; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci emu = p->emu; 2048c2ecf20Sopenharmony_ci if (snd_BUG_ON(!emu)) 2058c2ecf20Sopenharmony_ci return -ENXIO; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (format == GUS_PATCH) 2088c2ecf20Sopenharmony_ci rc = snd_soundfont_load_guspatch(emu->sflist, buf, count, 2098c2ecf20Sopenharmony_ci SF_CLIENT_NO(p->chset.port)); 2108c2ecf20Sopenharmony_ci else if (format == SNDRV_OSS_SOUNDFONT_PATCH) { 2118c2ecf20Sopenharmony_ci struct soundfont_patch_info patch; 2128c2ecf20Sopenharmony_ci if (count < (int)sizeof(patch)) 2138c2ecf20Sopenharmony_ci return -EINVAL; 2148c2ecf20Sopenharmony_ci if (copy_from_user(&patch, buf, sizeof(patch))) 2158c2ecf20Sopenharmony_ci return -EFAULT; 2168c2ecf20Sopenharmony_ci if (patch.type >= SNDRV_SFNT_LOAD_INFO && 2178c2ecf20Sopenharmony_ci patch.type <= SNDRV_SFNT_PROBE_DATA) 2188c2ecf20Sopenharmony_ci rc = snd_soundfont_load(emu->sflist, buf, count, SF_CLIENT_NO(p->chset.port)); 2198c2ecf20Sopenharmony_ci else { 2208c2ecf20Sopenharmony_ci if (emu->ops.load_fx) 2218c2ecf20Sopenharmony_ci rc = emu->ops.load_fx(emu, patch.type, patch.optarg, buf, count); 2228c2ecf20Sopenharmony_ci else 2238c2ecf20Sopenharmony_ci rc = -EINVAL; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci } else 2268c2ecf20Sopenharmony_ci rc = 0; 2278c2ecf20Sopenharmony_ci return rc; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/* 2328c2ecf20Sopenharmony_ci * ioctl 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_cistatic int 2358c2ecf20Sopenharmony_cisnd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned long ioarg) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct snd_emux_port *p; 2388c2ecf20Sopenharmony_ci struct snd_emux *emu; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (snd_BUG_ON(!arg)) 2418c2ecf20Sopenharmony_ci return -ENXIO; 2428c2ecf20Sopenharmony_ci p = arg->private_data; 2438c2ecf20Sopenharmony_ci if (snd_BUG_ON(!p)) 2448c2ecf20Sopenharmony_ci return -ENXIO; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci emu = p->emu; 2478c2ecf20Sopenharmony_ci if (snd_BUG_ON(!emu)) 2488c2ecf20Sopenharmony_ci return -ENXIO; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci switch (cmd) { 2518c2ecf20Sopenharmony_ci case SNDCTL_SEQ_RESETSAMPLES: 2528c2ecf20Sopenharmony_ci snd_soundfont_remove_samples(emu->sflist); 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci case SNDCTL_SYNTH_MEMAVL: 2568c2ecf20Sopenharmony_ci if (emu->memhdr) 2578c2ecf20Sopenharmony_ci return snd_util_mem_avail(emu->memhdr); 2588c2ecf20Sopenharmony_ci return 0; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci/* 2668c2ecf20Sopenharmony_ci * reset device 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_cistatic int 2698c2ecf20Sopenharmony_cisnd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct snd_emux_port *p; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (snd_BUG_ON(!arg)) 2748c2ecf20Sopenharmony_ci return -ENXIO; 2758c2ecf20Sopenharmony_ci p = arg->private_data; 2768c2ecf20Sopenharmony_ci if (snd_BUG_ON(!p)) 2778c2ecf20Sopenharmony_ci return -ENXIO; 2788c2ecf20Sopenharmony_ci snd_emux_reset_port(p); 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/* 2848c2ecf20Sopenharmony_ci * receive raw events: only SEQ_PRIVATE is accepted. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_cistatic int 2878c2ecf20Sopenharmony_cisnd_emux_event_oss_input(struct snd_seq_event *ev, int direct, void *private_data, 2888c2ecf20Sopenharmony_ci int atomic, int hop) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci struct snd_emux *emu; 2918c2ecf20Sopenharmony_ci struct snd_emux_port *p; 2928c2ecf20Sopenharmony_ci unsigned char cmd, *data; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci p = private_data; 2958c2ecf20Sopenharmony_ci if (snd_BUG_ON(!p)) 2968c2ecf20Sopenharmony_ci return -EINVAL; 2978c2ecf20Sopenharmony_ci emu = p->emu; 2988c2ecf20Sopenharmony_ci if (snd_BUG_ON(!emu)) 2998c2ecf20Sopenharmony_ci return -EINVAL; 3008c2ecf20Sopenharmony_ci if (ev->type != SNDRV_SEQ_EVENT_OSS) 3018c2ecf20Sopenharmony_ci return snd_emux_event_input(ev, direct, private_data, atomic, hop); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci data = ev->data.raw8.d; 3048c2ecf20Sopenharmony_ci /* only SEQ_PRIVATE is accepted */ 3058c2ecf20Sopenharmony_ci if (data[0] != 0xfe) 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci cmd = data[2] & _EMUX_OSS_MODE_VALUE_MASK; 3088c2ecf20Sopenharmony_ci if (data[2] & _EMUX_OSS_MODE_FLAG) 3098c2ecf20Sopenharmony_ci emuspec_control(emu, p, cmd, data, atomic, hop); 3108c2ecf20Sopenharmony_ci else 3118c2ecf20Sopenharmony_ci gusspec_control(emu, p, cmd, data, atomic, hop); 3128c2ecf20Sopenharmony_ci return 0; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/* 3178c2ecf20Sopenharmony_ci * OSS/AWE driver specific h/w controls 3188c2ecf20Sopenharmony_ci */ 3198c2ecf20Sopenharmony_cistatic void 3208c2ecf20Sopenharmony_ciemuspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, 3218c2ecf20Sopenharmony_ci unsigned char *event, int atomic, int hop) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci int voice; 3248c2ecf20Sopenharmony_ci unsigned short p1; 3258c2ecf20Sopenharmony_ci short p2; 3268c2ecf20Sopenharmony_ci int i; 3278c2ecf20Sopenharmony_ci struct snd_midi_channel *chan; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci voice = event[3]; 3308c2ecf20Sopenharmony_ci if (voice < 0 || voice >= port->chset.max_channels) 3318c2ecf20Sopenharmony_ci chan = NULL; 3328c2ecf20Sopenharmony_ci else 3338c2ecf20Sopenharmony_ci chan = &port->chset.channels[voice]; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci p1 = *(unsigned short *) &event[4]; 3368c2ecf20Sopenharmony_ci p2 = *(short *) &event[6]; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci switch (cmd) { 3398c2ecf20Sopenharmony_ci#if 0 /* don't do this atomically */ 3408c2ecf20Sopenharmony_ci case _EMUX_OSS_REMOVE_LAST_SAMPLES: 3418c2ecf20Sopenharmony_ci snd_soundfont_remove_unlocked(emu->sflist); 3428c2ecf20Sopenharmony_ci break; 3438c2ecf20Sopenharmony_ci#endif 3448c2ecf20Sopenharmony_ci case _EMUX_OSS_SEND_EFFECT: 3458c2ecf20Sopenharmony_ci if (chan) 3468c2ecf20Sopenharmony_ci snd_emux_send_effect_oss(port, chan, p1, p2); 3478c2ecf20Sopenharmony_ci break; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci case _EMUX_OSS_TERMINATE_ALL: 3508c2ecf20Sopenharmony_ci snd_emux_terminate_all(emu); 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci case _EMUX_OSS_TERMINATE_CHANNEL: 3548c2ecf20Sopenharmony_ci /*snd_emux_mute_channel(emu, chan);*/ 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci case _EMUX_OSS_RESET_CHANNEL: 3578c2ecf20Sopenharmony_ci /*snd_emux_channel_init(chset, chan);*/ 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci case _EMUX_OSS_RELEASE_ALL: 3618c2ecf20Sopenharmony_ci fake_event(emu, port, voice, MIDI_CTL_ALL_NOTES_OFF, 0, atomic, hop); 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci case _EMUX_OSS_NOTEOFF_ALL: 3648c2ecf20Sopenharmony_ci fake_event(emu, port, voice, MIDI_CTL_ALL_SOUNDS_OFF, 0, atomic, hop); 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci case _EMUX_OSS_INITIAL_VOLUME: 3688c2ecf20Sopenharmony_ci if (p2) { 3698c2ecf20Sopenharmony_ci port->volume_atten = (short)p1; 3708c2ecf20Sopenharmony_ci snd_emux_update_port(port, SNDRV_EMUX_UPDATE_VOLUME); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci break; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci case _EMUX_OSS_CHN_PRESSURE: 3758c2ecf20Sopenharmony_ci if (chan) { 3768c2ecf20Sopenharmony_ci chan->midi_pressure = p1; 3778c2ecf20Sopenharmony_ci snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_FMMOD|SNDRV_EMUX_UPDATE_FM2FRQ2); 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci case _EMUX_OSS_CHANNEL_MODE: 3828c2ecf20Sopenharmony_ci reset_port_mode(port, p1); 3838c2ecf20Sopenharmony_ci snd_emux_reset_port(port); 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci case _EMUX_OSS_DRUM_CHANNELS: 3878c2ecf20Sopenharmony_ci port->drum_flags = *(unsigned int*)&event[4]; 3888c2ecf20Sopenharmony_ci for (i = 0; i < port->chset.max_channels; i++) { 3898c2ecf20Sopenharmony_ci chan = &port->chset.channels[i]; 3908c2ecf20Sopenharmony_ci chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci case _EMUX_OSS_MISC_MODE: 3958c2ecf20Sopenharmony_ci if (p1 < EMUX_MD_END) 3968c2ecf20Sopenharmony_ci port->ctrls[p1] = p2; 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci case _EMUX_OSS_DEBUG_MODE: 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci default: 4028c2ecf20Sopenharmony_ci if (emu->ops.oss_ioctl) 4038c2ecf20Sopenharmony_ci emu->ops.oss_ioctl(emu, cmd, p1, p2); 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci/* 4098c2ecf20Sopenharmony_ci * GUS specific h/w controls 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci#include <linux/ultrasound.h> 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic void 4158c2ecf20Sopenharmony_cigusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, 4168c2ecf20Sopenharmony_ci unsigned char *event, int atomic, int hop) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci int voice; 4198c2ecf20Sopenharmony_ci unsigned short p1; 4208c2ecf20Sopenharmony_ci int plong; 4218c2ecf20Sopenharmony_ci struct snd_midi_channel *chan; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (port->port_mode != SNDRV_EMUX_PORT_MODE_OSS_SYNTH) 4248c2ecf20Sopenharmony_ci return; 4258c2ecf20Sopenharmony_ci if (cmd == _GUS_NUMVOICES) 4268c2ecf20Sopenharmony_ci return; 4278c2ecf20Sopenharmony_ci voice = event[3]; 4288c2ecf20Sopenharmony_ci if (voice < 0 || voice >= port->chset.max_channels) 4298c2ecf20Sopenharmony_ci return; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci chan = &port->chset.channels[voice]; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci p1 = *(unsigned short *) &event[4]; 4348c2ecf20Sopenharmony_ci plong = *(int*) &event[4]; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci switch (cmd) { 4378c2ecf20Sopenharmony_ci case _GUS_VOICESAMPLE: 4388c2ecf20Sopenharmony_ci chan->midi_program = p1; 4398c2ecf20Sopenharmony_ci return; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci case _GUS_VOICEBALA: 4428c2ecf20Sopenharmony_ci /* 0 to 15 --> 0 to 127 */ 4438c2ecf20Sopenharmony_ci chan->control[MIDI_CTL_MSB_PAN] = (int)p1 << 3; 4448c2ecf20Sopenharmony_ci snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PAN); 4458c2ecf20Sopenharmony_ci return; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci case _GUS_VOICEVOL: 4488c2ecf20Sopenharmony_ci case _GUS_VOICEVOL2: 4498c2ecf20Sopenharmony_ci /* not supported yet */ 4508c2ecf20Sopenharmony_ci return; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci case _GUS_RAMPRANGE: 4538c2ecf20Sopenharmony_ci case _GUS_RAMPRATE: 4548c2ecf20Sopenharmony_ci case _GUS_RAMPMODE: 4558c2ecf20Sopenharmony_ci case _GUS_RAMPON: 4568c2ecf20Sopenharmony_ci case _GUS_RAMPOFF: 4578c2ecf20Sopenharmony_ci /* volume ramping not supported */ 4588c2ecf20Sopenharmony_ci return; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci case _GUS_VOLUME_SCALE: 4618c2ecf20Sopenharmony_ci return; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci case _GUS_VOICE_POS: 4648c2ecf20Sopenharmony_ci#ifdef SNDRV_EMUX_USE_RAW_EFFECT 4658c2ecf20Sopenharmony_ci snd_emux_send_effect(port, chan, EMUX_FX_SAMPLE_START, 4668c2ecf20Sopenharmony_ci (short)(plong & 0x7fff), 4678c2ecf20Sopenharmony_ci EMUX_FX_FLAG_SET); 4688c2ecf20Sopenharmony_ci snd_emux_send_effect(port, chan, EMUX_FX_COARSE_SAMPLE_START, 4698c2ecf20Sopenharmony_ci (plong >> 15) & 0xffff, 4708c2ecf20Sopenharmony_ci EMUX_FX_FLAG_SET); 4718c2ecf20Sopenharmony_ci#endif 4728c2ecf20Sopenharmony_ci return; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci/* 4788c2ecf20Sopenharmony_ci * send an event to midi emulation 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_cistatic void 4818c2ecf20Sopenharmony_cifake_event(struct snd_emux *emu, struct snd_emux_port *port, int ch, int param, int val, int atomic, int hop) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct snd_seq_event ev; 4848c2ecf20Sopenharmony_ci memset(&ev, 0, sizeof(ev)); 4858c2ecf20Sopenharmony_ci ev.type = SNDRV_SEQ_EVENT_CONTROLLER; 4868c2ecf20Sopenharmony_ci ev.data.control.channel = ch; 4878c2ecf20Sopenharmony_ci ev.data.control.param = param; 4888c2ecf20Sopenharmony_ci ev.data.control.value = val; 4898c2ecf20Sopenharmony_ci snd_emux_event_input(&ev, 0, port, atomic, hop); 4908c2ecf20Sopenharmony_ci} 491