1 /* 2 * Interface for OSS sequencer emulation 3 * 4 * Copyright (C) 1999 Takashi Iwai <tiwai@suse.de> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * Changes 21 * 19990227 Steve Ratcliffe Made separate file and merged in latest 22 * midi emulation. 23 */ 24 25 26 #ifdef CONFIG_SND_SEQUENCER_OSS 27 28 #include <asm/uaccess.h> 29 #include <sound/core.h> 30 #include "emux_voice.h" 31 #include <sound/asoundef.h> 32 33 static int snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure); 34 static int snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg); 35 static int snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, 36 unsigned long ioarg); 37 static int snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, 38 const char __user *buf, int offs, int count); 39 static int snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg); 40 static int snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, 41 void *private, int atomic, int hop); 42 static void reset_port_mode(struct snd_emux_port *port, int midi_mode); 43 static void emuspec_control(struct snd_emux *emu, struct snd_emux_port *port, 44 int cmd, unsigned char *event, int atomic, int hop); 45 static void gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, 46 int cmd, unsigned char *event, int atomic, int hop); 47 static void fake_event(struct snd_emux *emu, struct snd_emux_port *port, 48 int ch, int param, int val, int atomic, int hop); 49 50 /* operators */ 51 static struct snd_seq_oss_callback oss_callback = { 52 .owner = THIS_MODULE, 53 .open = snd_emux_open_seq_oss, 54 .close = snd_emux_close_seq_oss, 55 .ioctl = snd_emux_ioctl_seq_oss, 56 .load_patch = snd_emux_load_patch_seq_oss, 57 .reset = snd_emux_reset_seq_oss, 58 }; 59 60 61 /* 62 * register OSS synth 63 */ 64 65 void 66 snd_emux_init_seq_oss(struct snd_emux *emu) 67 { 68 struct snd_seq_oss_reg *arg; 69 struct snd_seq_device *dev; 70 71 if (snd_seq_device_new(emu->card, 0, SNDRV_SEQ_DEV_ID_OSS, 72 sizeof(struct snd_seq_oss_reg), &dev) < 0) 73 return; 74 75 emu->oss_synth = dev; 76 strcpy(dev->name, emu->name); 77 arg = SNDRV_SEQ_DEVICE_ARGPTR(dev); 78 arg->type = SYNTH_TYPE_SAMPLE; 79 arg->subtype = SAMPLE_TYPE_AWE32; 80 arg->nvoices = emu->max_voices; 81 arg->oper = oss_callback; 82 arg->private_data = emu; 83 84 /* register to OSS synth table */ 85 snd_device_register(emu->card, dev); 86 } 87 88 89 /* 90 * unregister 91 */ 92 void 93 snd_emux_detach_seq_oss(struct snd_emux *emu) 94 { 95 if (emu->oss_synth) { 96 snd_device_free(emu->card, emu->oss_synth); 97 emu->oss_synth = NULL; 98 } 99 } 100 101 102 /* use port number as a unique soundfont client number */ 103 #define SF_CLIENT_NO(p) ((p) + 0x1000) 104 105 /* 106 * open port for OSS sequencer 107 */ 108 static int 109 snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure) 110 { 111 struct snd_emux *emu; 112 struct snd_emux_port *p; 113 struct snd_seq_port_callback callback; 114 char tmpname[64]; 115 116 emu = closure; 117 snd_assert(arg != NULL && emu != NULL, return -ENXIO); 118 119 mutex_lock(&emu->register_mutex); 120 121 if (!snd_emux_inc_count(emu)) { 122 mutex_unlock(&emu->register_mutex); 123 return -EFAULT; 124 } 125 126 memset(&callback, 0, sizeof(callback)); 127 callback.owner = THIS_MODULE; 128 callback.event_input = snd_emux_event_oss_input; 129 130 sprintf(tmpname, "%s OSS Port", emu->name); 131 p = snd_emux_create_port(emu, tmpname, 32, 132 1, &callback); 133 if (p == NULL) { 134 snd_printk("can't create port\n"); 135 snd_emux_dec_count(emu); 136 mutex_unlock(&emu->register_mutex); 137 return -ENOMEM; 138 } 139 140 /* fill the argument data */ 141 arg->private_data = p; 142 arg->addr.client = p->chset.client; 143 arg->addr.port = p->chset.port; 144 p->oss_arg = arg; 145 146 reset_port_mode(p, arg->seq_mode); 147 148 snd_emux_reset_port(p); 149 150 mutex_unlock(&emu->register_mutex); 151 return 0; 152 } 153 154 155 #define DEFAULT_DRUM_FLAGS ((1<<9) | (1<<25)) 156 157 /* 158 * reset port mode 159 */ 160 static void 161 reset_port_mode(struct snd_emux_port *port, int midi_mode) 162 { 163 if (midi_mode) { 164 port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_MIDI; 165 port->drum_flags = DEFAULT_DRUM_FLAGS; 166 port->volume_atten = 0; 167 port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_KEYPRESS; 168 } else { 169 port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_SYNTH; 170 port->drum_flags = 0; 171 port->volume_atten = 32; 172 port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS; 173 } 174 } 175 176 177 /* 178 * close port 179 */ 180 static int 181 snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg) 182 { 183 struct snd_emux *emu; 184 struct snd_emux_port *p; 185 186 snd_assert(arg != NULL, return -ENXIO); 187 p = arg->private_data; 188 snd_assert(p != NULL, return -ENXIO); 189 190 emu = p->emu; 191 snd_assert(emu != NULL, return -ENXIO); 192 193 mutex_lock(&emu->register_mutex); 194 snd_emux_sounds_off_all(p); 195 snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port)); 196 snd_seq_event_port_detach(p->chset.client, p->chset.port); 197 snd_emux_dec_count(emu); 198 199 mutex_unlock(&emu->register_mutex); 200 return 0; 201 } 202 203 204 /* 205 * load patch 206 */ 207 static int 208 snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, 209 const char __user *buf, int offs, int count) 210 { 211 struct snd_emux *emu; 212 struct snd_emux_port *p; 213 int rc; 214 215 snd_assert(arg != NULL, return -ENXIO); 216 p = arg->private_data; 217 snd_assert(p != NULL, return -ENXIO); 218 219 emu = p->emu; 220 snd_assert(emu != NULL, return -ENXIO); 221 222 if (format == GUS_PATCH) 223 rc = snd_soundfont_load_guspatch(emu->sflist, buf, count, 224 SF_CLIENT_NO(p->chset.port)); 225 else if (format == SNDRV_OSS_SOUNDFONT_PATCH) { 226 struct soundfont_patch_info patch; 227 if (count < (int)sizeof(patch)) 228 rc = -EINVAL; 229 if (copy_from_user(&patch, buf, sizeof(patch))) 230 rc = -EFAULT; 231 if (patch.type >= SNDRV_SFNT_LOAD_INFO && 232 patch.type <= SNDRV_SFNT_PROBE_DATA) 233 rc = snd_soundfont_load(emu->sflist, buf, count, SF_CLIENT_NO(p->chset.port)); 234 else { 235 if (emu->ops.load_fx) 236 rc = emu->ops.load_fx(emu, patch.type, patch.optarg, buf, count); 237 else 238 rc = -EINVAL; 239 } 240 } else 241 rc = 0; 242 return rc; 243 } 244 245 246 /* 247 * ioctl 248 */ 249 static int 250 snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned long ioarg) 251 { 252 struct snd_emux_port *p; 253 struct snd_emux *emu; 254 255 snd_assert(arg != NULL, return -ENXIO); 256 p = arg->private_data; 257 snd_assert(p != NULL, return -ENXIO); 258 259 emu = p->emu; 260 snd_assert(emu != NULL, return -ENXIO); 261 262 switch (cmd) { 263 case SNDCTL_SEQ_RESETSAMPLES: 264 snd_soundfont_remove_samples(emu->sflist); 265 return 0; 266 267 case SNDCTL_SYNTH_MEMAVL: 268 if (emu->memhdr) 269 return snd_util_mem_avail(emu->memhdr); 270 return 0; 271 } 272 273 return 0; 274 } 275 276 277 /* 278 * reset device 279 */ 280 static int 281 snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg) 282 { 283 struct snd_emux_port *p; 284 285 snd_assert(arg != NULL, return -ENXIO); 286 p = arg->private_data; 287 snd_assert(p != NULL, return -ENXIO); 288 snd_emux_reset_port(p); 289 return 0; 290 } 291 292 293 /* 294 * receive raw events: only SEQ_PRIVATE is accepted. 295 */ 296 static int 297 snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, void *private_data, 298 int atomic, int hop) 299 { 300 struct snd_emux *emu; 301 struct snd_emux_port *p; 302 unsigned char cmd, *data; 303 304 p = private_data; 305 snd_assert(p != NULL, return -EINVAL); 306 emu = p->emu; 307 snd_assert(emu != NULL, return -EINVAL); 308 if (ev->type != SNDRV_SEQ_EVENT_OSS) 309 return snd_emux_event_input(ev, direct, private_data, atomic, hop); 310 311 data = ev->data.raw8.d; 312 /* only SEQ_PRIVATE is accepted */ 313 if (data[0] != 0xfe) 314 return 0; 315 cmd = data[2] & _EMUX_OSS_MODE_VALUE_MASK; 316 if (data[2] & _EMUX_OSS_MODE_FLAG) 317 emuspec_control(emu, p, cmd, data, atomic, hop); 318 else 319 gusspec_control(emu, p, cmd, data, atomic, hop); 320 return 0; 321 } 322 323 324 /* 325 * OSS/AWE driver specific h/w controls 326 */ 327 static void 328 emuspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, 329 unsigned char *event, int atomic, int hop) 330 { 331 int voice; 332 unsigned short p1; 333 short p2; 334 int i; 335 struct snd_midi_channel *chan; 336 337 voice = event[3]; 338 if (voice < 0 || voice >= port->chset.max_channels) 339 chan = NULL; 340 else 341 chan = &port->chset.channels[voice]; 342 343 p1 = *(unsigned short *) &event[4]; 344 p2 = *(short *) &event[6]; 345 346 switch (cmd) { 347 #if 0 /* don't do this atomically */ 348 case _EMUX_OSS_REMOVE_LAST_SAMPLES: 349 snd_soundfont_remove_unlocked(emu->sflist); 350 break; 351 #endif 352 case _EMUX_OSS_SEND_EFFECT: 353 if (chan) 354 snd_emux_send_effect_oss(port, chan, p1, p2); 355 break; 356 357 case _EMUX_OSS_TERMINATE_ALL: 358 snd_emux_terminate_all(emu); 359 break; 360 361 case _EMUX_OSS_TERMINATE_CHANNEL: 362 /*snd_emux_mute_channel(emu, chan);*/ 363 break; 364 case _EMUX_OSS_RESET_CHANNEL: 365 /*snd_emux_channel_init(chset, chan);*/ 366 break; 367 368 case _EMUX_OSS_RELEASE_ALL: 369 fake_event(emu, port, voice, MIDI_CTL_ALL_NOTES_OFF, 0, atomic, hop); 370 break; 371 case _EMUX_OSS_NOTEOFF_ALL: 372 fake_event(emu, port, voice, MIDI_CTL_ALL_SOUNDS_OFF, 0, atomic, hop); 373 break; 374 375 case _EMUX_OSS_INITIAL_VOLUME: 376 if (p2) { 377 port->volume_atten = (short)p1; 378 snd_emux_update_port(port, SNDRV_EMUX_UPDATE_VOLUME); 379 } 380 break; 381 382 case _EMUX_OSS_CHN_PRESSURE: 383 if (chan) { 384 chan->midi_pressure = p1; 385 snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_FMMOD|SNDRV_EMUX_UPDATE_FM2FRQ2); 386 } 387 break; 388 389 case _EMUX_OSS_CHANNEL_MODE: 390 reset_port_mode(port, p1); 391 snd_emux_reset_port(port); 392 break; 393 394 case _EMUX_OSS_DRUM_CHANNELS: 395 port->drum_flags = *(unsigned int*)&event[4]; 396 for (i = 0; i < port->chset.max_channels; i++) { 397 chan = &port->chset.channels[i]; 398 chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0; 399 } 400 break; 401 402 case _EMUX_OSS_MISC_MODE: 403 if (p1 < EMUX_MD_END) 404 port->ctrls[p1] = p2; 405 break; 406 case _EMUX_OSS_DEBUG_MODE: 407 break; 408 409 default: 410 if (emu->ops.oss_ioctl) 411 emu->ops.oss_ioctl(emu, cmd, p1, p2); 412 break; 413 } 414 } 415 416 /* 417 * GUS specific h/w controls 418 */ 419 420 #include <linux/ultrasound.h> 421 422 static void 423 gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, 424 unsigned char *event, int atomic, int hop) 425 { 426 int voice; 427 unsigned short p1; 428 short p2; 429 int plong; 430 struct snd_midi_channel *chan; 431 432 if (port->port_mode != SNDRV_EMUX_PORT_MODE_OSS_SYNTH) 433 return; 434 if (cmd == _GUS_NUMVOICES) 435 return; 436 voice = event[3]; 437 if (voice < 0 || voice >= port->chset.max_channels) 438 return; 439 440 chan = &port->chset.channels[voice]; 441 442 p1 = *(unsigned short *) &event[4]; 443 p2 = *(short *) &event[6]; 444 plong = *(int*) &event[4]; 445 446 switch (cmd) { 447 case _GUS_VOICESAMPLE: 448 chan->midi_program = p1; 449 return; 450 451 case _GUS_VOICEBALA: 452 /* 0 to 15 --> 0 to 127 */ 453 chan->control[MIDI_CTL_MSB_PAN] = (int)p1 << 3; 454 snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PAN); 455 return; 456 457 case _GUS_VOICEVOL: 458 case _GUS_VOICEVOL2: 459 /* not supported yet */ 460 return; 461 462 case _GUS_RAMPRANGE: 463 case _GUS_RAMPRATE: 464 case _GUS_RAMPMODE: 465 case _GUS_RAMPON: 466 case _GUS_RAMPOFF: 467 /* volume ramping not supported */ 468 return; 469 470 case _GUS_VOLUME_SCALE: 471 return; 472 473 case _GUS_VOICE_POS: 474 #ifdef SNDRV_EMUX_USE_RAW_EFFECT 475 snd_emux_send_effect(port, chan, EMUX_FX_SAMPLE_START, 476 (short)(plong & 0x7fff), 477 EMUX_FX_FLAG_SET); 478 snd_emux_send_effect(port, chan, EMUX_FX_COARSE_SAMPLE_START, 479 (plong >> 15) & 0xffff, 480 EMUX_FX_FLAG_SET); 481 #endif 482 return; 483 } 484 } 485 486 487 /* 488 * send an event to midi emulation 489 */ 490 static void 491 fake_event(struct snd_emux *emu, struct snd_emux_port *port, int ch, int param, int val, int atomic, int hop) 492 { 493 struct snd_seq_event ev; 494 memset(&ev, 0, sizeof(ev)); 495 ev.type = SNDRV_SEQ_EVENT_CONTROLLER; 496 ev.data.control.channel = ch; 497 ev.data.control.param = param; 498 ev.data.control.value = val; 499 snd_emux_event_input(&ev, 0, port, atomic, hop); 500 } 501 502 #endif /* CONFIG_SND_SEQUENCER_OSS */ 503