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