11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Interface for OSS sequencer emulation 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2000 Uros Bizjak <uros@kss-loka.si> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 81da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 91da177e4SLinus Torvalds * (at your option) any later version. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 121da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 131da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141da177e4SLinus Torvalds * GNU General Public License for more details. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 171da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 181da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 191da177e4SLinus Torvalds */ 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #include "opl3_voice.h" 221da177e4SLinus Torvalds #include <linux/slab.h> 231da177e4SLinus Torvalds 24*5b1646a8STakashi Iwai static int snd_opl3_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure); 25*5b1646a8STakashi Iwai static int snd_opl3_close_seq_oss(struct snd_seq_oss_arg *arg); 26*5b1646a8STakashi Iwai static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned long ioarg); 27*5b1646a8STakashi Iwai static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, const char __user *buf, int offs, int count); 28*5b1646a8STakashi Iwai static int snd_opl3_reset_seq_oss(struct snd_seq_oss_arg *arg); 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* */ 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds static inline mm_segment_t snd_enter_user(void) 331da177e4SLinus Torvalds { 341da177e4SLinus Torvalds mm_segment_t fs = get_fs(); 351da177e4SLinus Torvalds set_fs(get_ds()); 361da177e4SLinus Torvalds return fs; 371da177e4SLinus Torvalds } 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds static inline void snd_leave_user(mm_segment_t fs) 401da177e4SLinus Torvalds { 411da177e4SLinus Torvalds set_fs(fs); 421da177e4SLinus Torvalds } 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds /* operators */ 451da177e4SLinus Torvalds 46*5b1646a8STakashi Iwai extern struct snd_midi_op opl3_ops; 471da177e4SLinus Torvalds 48*5b1646a8STakashi Iwai static struct snd_seq_oss_callback oss_callback = { 491da177e4SLinus Torvalds .owner = THIS_MODULE, 501da177e4SLinus Torvalds .open = snd_opl3_open_seq_oss, 511da177e4SLinus Torvalds .close = snd_opl3_close_seq_oss, 521da177e4SLinus Torvalds .ioctl = snd_opl3_ioctl_seq_oss, 531da177e4SLinus Torvalds .load_patch = snd_opl3_load_patch_seq_oss, 541da177e4SLinus Torvalds .reset = snd_opl3_reset_seq_oss, 551da177e4SLinus Torvalds }; 561da177e4SLinus Torvalds 57*5b1646a8STakashi Iwai static int snd_opl3_oss_event_input(struct snd_seq_event *ev, int direct, 581da177e4SLinus Torvalds void *private_data, int atomic, int hop) 591da177e4SLinus Torvalds { 60*5b1646a8STakashi Iwai struct snd_opl3 *opl3 = private_data; 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds if (ev->type != SNDRV_SEQ_EVENT_OSS) 631da177e4SLinus Torvalds snd_midi_process_event(&opl3_ops, ev, opl3->oss_chset); 641da177e4SLinus Torvalds return 0; 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds /* ------------------------------ */ 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds static void snd_opl3_oss_free_port(void *private_data) 701da177e4SLinus Torvalds { 71*5b1646a8STakashi Iwai struct snd_opl3 *opl3 = private_data; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds snd_midi_channel_free_set(opl3->oss_chset); 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 76*5b1646a8STakashi Iwai static int snd_opl3_oss_create_port(struct snd_opl3 * opl3) 771da177e4SLinus Torvalds { 78*5b1646a8STakashi Iwai struct snd_seq_port_callback callbacks; 791da177e4SLinus Torvalds char name[32]; 801da177e4SLinus Torvalds int voices, opl_ver; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds voices = (opl3->hardware < OPL3_HW_OPL3) ? 831da177e4SLinus Torvalds MAX_OPL2_VOICES : MAX_OPL3_VOICES; 841da177e4SLinus Torvalds opl3->oss_chset = snd_midi_channel_alloc_set(voices); 851da177e4SLinus Torvalds if (opl3->oss_chset == NULL) 861da177e4SLinus Torvalds return -ENOMEM; 871da177e4SLinus Torvalds opl3->oss_chset->private_data = opl3; 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds memset(&callbacks, 0, sizeof(callbacks)); 901da177e4SLinus Torvalds callbacks.owner = THIS_MODULE; 911da177e4SLinus Torvalds callbacks.event_input = snd_opl3_oss_event_input; 921da177e4SLinus Torvalds callbacks.private_free = snd_opl3_oss_free_port; 931da177e4SLinus Torvalds callbacks.private_data = opl3; 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds opl_ver = (opl3->hardware & OPL3_HW_MASK) >> 8; 961da177e4SLinus Torvalds sprintf(name, "OPL%i OSS Port", opl_ver); 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds opl3->oss_chset->client = opl3->seq_client; 991da177e4SLinus Torvalds opl3->oss_chset->port = snd_seq_event_port_attach(opl3->seq_client, &callbacks, 1001da177e4SLinus Torvalds SNDRV_SEQ_PORT_CAP_WRITE, 1011da177e4SLinus Torvalds SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | 1021da177e4SLinus Torvalds SNDRV_SEQ_PORT_TYPE_MIDI_GM | 1031da177e4SLinus Torvalds SNDRV_SEQ_PORT_TYPE_SYNTH, 1041da177e4SLinus Torvalds voices, voices, 1051da177e4SLinus Torvalds name); 1061da177e4SLinus Torvalds if (opl3->oss_chset->port < 0) { 1071da177e4SLinus Torvalds snd_midi_channel_free_set(opl3->oss_chset); 1081da177e4SLinus Torvalds return opl3->oss_chset->port; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds return 0; 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds /* ------------------------------ */ 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds /* register OSS synth */ 116*5b1646a8STakashi Iwai void snd_opl3_init_seq_oss(struct snd_opl3 *opl3, char *name) 1171da177e4SLinus Torvalds { 118*5b1646a8STakashi Iwai struct snd_seq_oss_reg *arg; 119*5b1646a8STakashi Iwai struct snd_seq_device *dev; 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds if (snd_seq_device_new(opl3->card, 0, SNDRV_SEQ_DEV_ID_OSS, 122*5b1646a8STakashi Iwai sizeof(struct snd_seq_oss_reg), &dev) < 0) 1231da177e4SLinus Torvalds return; 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds opl3->oss_seq_dev = dev; 1261da177e4SLinus Torvalds strlcpy(dev->name, name, sizeof(dev->name)); 1271da177e4SLinus Torvalds arg = SNDRV_SEQ_DEVICE_ARGPTR(dev); 1281da177e4SLinus Torvalds arg->type = SYNTH_TYPE_FM; 1291da177e4SLinus Torvalds if (opl3->hardware < OPL3_HW_OPL3) { 1301da177e4SLinus Torvalds arg->subtype = FM_TYPE_ADLIB; 1311da177e4SLinus Torvalds arg->nvoices = MAX_OPL2_VOICES; 1321da177e4SLinus Torvalds } else { 1331da177e4SLinus Torvalds arg->subtype = FM_TYPE_OPL3; 1341da177e4SLinus Torvalds arg->nvoices = MAX_OPL3_VOICES; 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds arg->oper = oss_callback; 1371da177e4SLinus Torvalds arg->private_data = opl3; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds snd_opl3_oss_create_port(opl3); 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds /* register to OSS synth table */ 1421da177e4SLinus Torvalds snd_device_register(opl3->card, dev); 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds /* unregister */ 146*5b1646a8STakashi Iwai void snd_opl3_free_seq_oss(struct snd_opl3 *opl3) 1471da177e4SLinus Torvalds { 1481da177e4SLinus Torvalds if (opl3->oss_seq_dev) { 1491da177e4SLinus Torvalds snd_device_free(opl3->card, opl3->oss_seq_dev); 1501da177e4SLinus Torvalds opl3->oss_seq_dev = NULL; 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds /* ------------------------------ */ 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds /* open OSS sequencer */ 157*5b1646a8STakashi Iwai static int snd_opl3_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) 1581da177e4SLinus Torvalds { 159*5b1646a8STakashi Iwai struct snd_opl3 *opl3 = closure; 1601da177e4SLinus Torvalds int err; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds snd_assert(arg != NULL, return -ENXIO); 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds if ((err = snd_opl3_synth_setup(opl3)) < 0) 1651da177e4SLinus Torvalds return err; 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds /* fill the argument data */ 1681da177e4SLinus Torvalds arg->private_data = opl3; 1691da177e4SLinus Torvalds arg->addr.client = opl3->oss_chset->client; 1701da177e4SLinus Torvalds arg->addr.port = opl3->oss_chset->port; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds if ((err = snd_opl3_synth_use_inc(opl3)) < 0) 1731da177e4SLinus Torvalds return err; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds opl3->synth_mode = SNDRV_OPL3_MODE_SYNTH; 1761da177e4SLinus Torvalds return 0; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds /* close OSS sequencer */ 180*5b1646a8STakashi Iwai static int snd_opl3_close_seq_oss(struct snd_seq_oss_arg *arg) 1811da177e4SLinus Torvalds { 182*5b1646a8STakashi Iwai struct snd_opl3 *opl3; 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds snd_assert(arg != NULL, return -ENXIO); 1851da177e4SLinus Torvalds opl3 = arg->private_data; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds snd_opl3_synth_cleanup(opl3); 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds snd_opl3_synth_use_dec(opl3); 1901da177e4SLinus Torvalds return 0; 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds /* load patch */ 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds /* offsets for SBI params */ 1961da177e4SLinus Torvalds #define AM_VIB 0 1971da177e4SLinus Torvalds #define KSL_LEVEL 2 1981da177e4SLinus Torvalds #define ATTACK_DECAY 4 1991da177e4SLinus Torvalds #define SUSTAIN_RELEASE 6 2001da177e4SLinus Torvalds #define WAVE_SELECT 8 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds /* offset for SBI instrument */ 2031da177e4SLinus Torvalds #define CONNECTION 10 2041da177e4SLinus Torvalds #define OFFSET_4OP 11 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds /* from sound_config.h */ 2071da177e4SLinus Torvalds #define SBFM_MAXINSTR 256 2081da177e4SLinus Torvalds 209*5b1646a8STakashi Iwai static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, 2101da177e4SLinus Torvalds const char __user *buf, int offs, int count) 2111da177e4SLinus Torvalds { 212*5b1646a8STakashi Iwai struct snd_opl3 *opl3; 2131da177e4SLinus Torvalds int err = -EINVAL; 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds snd_assert(arg != NULL, return -ENXIO); 2161da177e4SLinus Torvalds opl3 = arg->private_data; 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds if ((format == FM_PATCH) || (format == OPL3_PATCH)) { 2191da177e4SLinus Torvalds struct sbi_instrument sbi; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds size_t size; 222*5b1646a8STakashi Iwai struct snd_seq_instr_header *put; 223*5b1646a8STakashi Iwai struct snd_seq_instr_data *data; 224*5b1646a8STakashi Iwai struct fm_xinstrument *xinstr; 2251da177e4SLinus Torvalds 226*5b1646a8STakashi Iwai struct snd_seq_event ev; 2271da177e4SLinus Torvalds int i; 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds mm_segment_t fs; 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds if (count < (int)sizeof(sbi)) { 2321da177e4SLinus Torvalds snd_printk("FM Error: Patch record too short\n"); 2331da177e4SLinus Torvalds return -EINVAL; 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds if (copy_from_user(&sbi, buf, sizeof(sbi))) 2361da177e4SLinus Torvalds return -EFAULT; 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) { 2391da177e4SLinus Torvalds snd_printk("FM Error: Invalid instrument number %d\n", sbi.channel); 2401da177e4SLinus Torvalds return -EINVAL; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 243*5b1646a8STakashi Iwai size = sizeof(*put) + sizeof(struct fm_xinstrument); 244561b220aSTakashi Iwai put = kzalloc(size, GFP_KERNEL); 2451da177e4SLinus Torvalds if (put == NULL) 2461da177e4SLinus Torvalds return -ENOMEM; 2471da177e4SLinus Torvalds /* build header */ 2481da177e4SLinus Torvalds data = &put->data; 2491da177e4SLinus Torvalds data->type = SNDRV_SEQ_INSTR_ATYPE_DATA; 2501da177e4SLinus Torvalds strcpy(data->data.format, SNDRV_SEQ_INSTR_ID_OPL2_3); 2511da177e4SLinus Torvalds /* build data section */ 252*5b1646a8STakashi Iwai xinstr = (struct fm_xinstrument *)(data + 1); 2531da177e4SLinus Torvalds xinstr->stype = FM_STRU_INSTR; 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds for (i = 0; i < 2; i++) { 2561da177e4SLinus Torvalds xinstr->op[i].am_vib = sbi.operators[AM_VIB + i]; 2571da177e4SLinus Torvalds xinstr->op[i].ksl_level = sbi.operators[KSL_LEVEL + i]; 2581da177e4SLinus Torvalds xinstr->op[i].attack_decay = sbi.operators[ATTACK_DECAY + i]; 2591da177e4SLinus Torvalds xinstr->op[i].sustain_release = sbi.operators[SUSTAIN_RELEASE + i]; 2601da177e4SLinus Torvalds xinstr->op[i].wave_select = sbi.operators[WAVE_SELECT + i]; 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds xinstr->feedback_connection[0] = sbi.operators[CONNECTION]; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds if (format == OPL3_PATCH) { 2651da177e4SLinus Torvalds xinstr->type = FM_PATCH_OPL3; 2661da177e4SLinus Torvalds for (i = 0; i < 2; i++) { 2671da177e4SLinus Torvalds xinstr->op[i+2].am_vib = sbi.operators[OFFSET_4OP + AM_VIB + i]; 2681da177e4SLinus Torvalds xinstr->op[i+2].ksl_level = sbi.operators[OFFSET_4OP + KSL_LEVEL + i]; 2691da177e4SLinus Torvalds xinstr->op[i+2].attack_decay = sbi.operators[OFFSET_4OP + ATTACK_DECAY + i]; 2701da177e4SLinus Torvalds xinstr->op[i+2].sustain_release = sbi.operators[OFFSET_4OP + SUSTAIN_RELEASE + i]; 2711da177e4SLinus Torvalds xinstr->op[i+2].wave_select = sbi.operators[OFFSET_4OP + WAVE_SELECT + i]; 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds xinstr->feedback_connection[1] = sbi.operators[OFFSET_4OP + CONNECTION]; 2741da177e4SLinus Torvalds } else { 2751da177e4SLinus Torvalds xinstr->type = FM_PATCH_OPL2; 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds put->id.instr.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3; 2791da177e4SLinus Torvalds put->id.instr.bank = 127; 2801da177e4SLinus Torvalds put->id.instr.prg = sbi.channel; 2811da177e4SLinus Torvalds put->cmd = SNDRV_SEQ_INSTR_PUT_CMD_CREATE; 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds memset (&ev, 0, sizeof(ev)); 2841da177e4SLinus Torvalds ev.source.client = SNDRV_SEQ_CLIENT_OSS; 2851da177e4SLinus Torvalds ev.dest = arg->addr; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds ev.flags = SNDRV_SEQ_EVENT_LENGTH_VARUSR; 2881da177e4SLinus Torvalds ev.queue = SNDRV_SEQ_QUEUE_DIRECT; 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds fs = snd_enter_user(); 2911da177e4SLinus Torvalds __again: 2921da177e4SLinus Torvalds ev.type = SNDRV_SEQ_EVENT_INSTR_PUT; 2931da177e4SLinus Torvalds ev.data.ext.len = size; 2941da177e4SLinus Torvalds ev.data.ext.ptr = put; 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds err = snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev, 2971da177e4SLinus Torvalds opl3->seq_client, 0, 0); 2981da177e4SLinus Torvalds if (err == -EBUSY) { 299*5b1646a8STakashi Iwai struct snd_seq_instr_header remove; 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds memset (&remove, 0, sizeof(remove)); 3021da177e4SLinus Torvalds remove.cmd = SNDRV_SEQ_INSTR_FREE_CMD_SINGLE; 3031da177e4SLinus Torvalds remove.id.instr = put->id.instr; 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds /* remove instrument */ 3061da177e4SLinus Torvalds ev.type = SNDRV_SEQ_EVENT_INSTR_FREE; 3071da177e4SLinus Torvalds ev.data.ext.len = sizeof(remove); 3081da177e4SLinus Torvalds ev.data.ext.ptr = &remove; 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev, 3111da177e4SLinus Torvalds opl3->seq_client, 0, 0); 3121da177e4SLinus Torvalds goto __again; 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds snd_leave_user(fs); 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds kfree(put); 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds return err; 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds /* ioctl */ 322*5b1646a8STakashi Iwai static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, 3231da177e4SLinus Torvalds unsigned long ioarg) 3241da177e4SLinus Torvalds { 325*5b1646a8STakashi Iwai struct snd_opl3 *opl3; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds snd_assert(arg != NULL, return -ENXIO); 3281da177e4SLinus Torvalds opl3 = arg->private_data; 3291da177e4SLinus Torvalds switch (cmd) { 3301da177e4SLinus Torvalds case SNDCTL_FM_LOAD_INSTR: 3311da177e4SLinus Torvalds snd_printk("OPL3: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n"); 3321da177e4SLinus Torvalds return -EINVAL; 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds case SNDCTL_SYNTH_MEMAVL: 3351da177e4SLinus Torvalds return 0x7fffffff; 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds case SNDCTL_FM_4OP_ENABLE: 3381da177e4SLinus Torvalds // handled automatically by OPL instrument type 3391da177e4SLinus Torvalds return 0; 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds default: 3421da177e4SLinus Torvalds return -EINVAL; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds return 0; 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds /* reset device */ 348*5b1646a8STakashi Iwai static int snd_opl3_reset_seq_oss(struct snd_seq_oss_arg *arg) 3491da177e4SLinus Torvalds { 350*5b1646a8STakashi Iwai struct snd_opl3 *opl3; 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds snd_assert(arg != NULL, return -ENXIO); 3531da177e4SLinus Torvalds opl3 = arg->private_data; 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds return 0; 3561da177e4SLinus Torvalds } 357