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 33static int snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure); 34static int snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg); 35static int snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, 36 unsigned long ioarg); 37static int snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, 38 const char __user *buf, int offs, int count); 39static int snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg); 40static int snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, 41 void *private, int atomic, int hop); 42static void reset_port_mode(struct snd_emux_port *port, int midi_mode); 43static void emuspec_control(struct snd_emux *emu, struct snd_emux_port *port, 44 int cmd, unsigned char *event, int atomic, int hop); 45static void gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, 46 int cmd, unsigned char *event, int atomic, int hop); 47static 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 */ 51static 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 65void 66snd_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 */ 92void 93snd_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 */ 108static int 109snd_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 if (snd_BUG_ON(!arg || !emu)) 118 return -ENXIO; 119 120 mutex_lock(&emu->register_mutex); 121 122 if (!snd_emux_inc_count(emu)) { 123 mutex_unlock(&emu->register_mutex); 124 return -EFAULT; 125 } 126 127 memset(&callback, 0, sizeof(callback)); 128 callback.owner = THIS_MODULE; 129 callback.event_input = snd_emux_event_oss_input; 130 131 sprintf(tmpname, "%s OSS Port", emu->name); 132 p = snd_emux_create_port(emu, tmpname, 32, 133 1, &callback); 134 if (p == NULL) { 135 snd_printk(KERN_ERR "can't create port\n"); 136 snd_emux_dec_count(emu); 137 mutex_unlock(&emu->register_mutex); 138 return -ENOMEM; 139 } 140 141 /* fill the argument data */ 142 arg->private_data = p; 143 arg->addr.client = p->chset.client; 144 arg->addr.port = p->chset.port; 145 p->oss_arg = arg; 146 147 reset_port_mode(p, arg->seq_mode); 148 149 snd_emux_reset_port(p); 150 151 mutex_unlock(&emu->register_mutex); 152 return 0; 153} 154 155 156#define DEFAULT_DRUM_FLAGS ((1<<9) | (1<<25)) 157 158/* 159 * reset port mode 160 */ 161static void 162reset_port_mode(struct snd_emux_port *port, int midi_mode) 163{ 164 if (midi_mode) { 165 port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_MIDI; 166 port->drum_flags = DEFAULT_DRUM_FLAGS; 167 port->volume_atten = 0; 168 port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_KEYPRESS; 169 } else { 170 port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_SYNTH; 171 port->drum_flags = 0; 172 port->volume_atten = 32; 173 port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS; 174 } 175} 176 177 178/* 179 * close port 180 */ 181static int 182snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg) 183{ 184 struct snd_emux *emu; 185 struct snd_emux_port *p; 186 187 if (snd_BUG_ON(!arg)) 188 return -ENXIO; 189 p = arg->private_data; 190 if (snd_BUG_ON(!p)) 191 return -ENXIO; 192 193 emu = p->emu; 194 if (snd_BUG_ON(!emu)) 195 return -ENXIO; 196 197 mutex_lock(&emu->register_mutex); 198 snd_emux_sounds_off_all(p); 199 snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port)); 200 snd_seq_event_port_detach(p->chset.client, p->chset.port); 201 snd_emux_dec_count(emu); 202 203 mutex_unlock(&emu->register_mutex); 204 return 0; 205} 206 207 208/* 209 * load patch 210 */ 211static int 212snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, 213 const char __user *buf, int offs, int count) 214{ 215 struct snd_emux *emu; 216 struct snd_emux_port *p; 217 int rc; 218 219 if (snd_BUG_ON(!arg)) 220 return -ENXIO; 221 p = arg->private_data; 222 if (snd_BUG_ON(!p)) 223 return -ENXIO; 224 225 emu = p->emu; 226 if (snd_BUG_ON(!emu)) 227 return -ENXIO; 228 229 if (format == GUS_PATCH) 230 rc = snd_soundfont_load_guspatch(emu->sflist, buf, count, 231 SF_CLIENT_NO(p->chset.port)); 232 else if (format == SNDRV_OSS_SOUNDFONT_PATCH) { 233 struct soundfont_patch_info patch; 234 if (count < (int)sizeof(patch)) 235 rc = -EINVAL; 236 if (copy_from_user(&patch, buf, sizeof(patch))) 237 rc = -EFAULT; 238 if (patch.type >= SNDRV_SFNT_LOAD_INFO && 239 patch.type <= SNDRV_SFNT_PROBE_DATA) 240 rc = snd_soundfont_load(emu->sflist, buf, count, SF_CLIENT_NO(p->chset.port)); 241 else { 242 if (emu->ops.load_fx) 243 rc = emu->ops.load_fx(emu, patch.type, patch.optarg, buf, count); 244 else 245 rc = -EINVAL; 246 } 247 } else 248 rc = 0; 249 return rc; 250} 251 252 253/* 254 * ioctl 255 */ 256static int 257snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned long ioarg) 258{ 259 struct snd_emux_port *p; 260 struct snd_emux *emu; 261 262 if (snd_BUG_ON(!arg)) 263 return -ENXIO; 264 p = arg->private_data; 265 if (snd_BUG_ON(!p)) 266 return -ENXIO; 267 268 emu = p->emu; 269 if (snd_BUG_ON(!emu)) 270 return -ENXIO; 271 272 switch (cmd) { 273 case SNDCTL_SEQ_RESETSAMPLES: 274 snd_soundfont_remove_samples(emu->sflist); 275 return 0; 276 277 case SNDCTL_SYNTH_MEMAVL: 278 if (emu->memhdr) 279 return snd_util_mem_avail(emu->memhdr); 280 return 0; 281 } 282 283 return 0; 284} 285 286 287/* 288 * reset device 289 */ 290static int 291snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg) 292{ 293 struct snd_emux_port *p; 294 295 if (snd_BUG_ON(!arg)) 296 return -ENXIO; 297 p = arg->private_data; 298 if (snd_BUG_ON(!p)) 299 return -ENXIO; 300 snd_emux_reset_port(p); 301 return 0; 302} 303 304 305/* 306 * receive raw events: only SEQ_PRIVATE is accepted. 307 */ 308static int 309snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, void *private_data, 310 int atomic, int hop) 311{ 312 struct snd_emux *emu; 313 struct snd_emux_port *p; 314 unsigned char cmd, *data; 315 316 p = private_data; 317 if (snd_BUG_ON(!p)) 318 return -EINVAL; 319 emu = p->emu; 320 if (snd_BUG_ON(!emu)) 321 return -EINVAL; 322 if (ev->type != SNDRV_SEQ_EVENT_OSS) 323 return snd_emux_event_input(ev, direct, private_data, atomic, hop); 324 325 data = ev->data.raw8.d; 326 /* only SEQ_PRIVATE is accepted */ 327 if (data[0] != 0xfe) 328 return 0; 329 cmd = data[2] & _EMUX_OSS_MODE_VALUE_MASK; 330 if (data[2] & _EMUX_OSS_MODE_FLAG) 331 emuspec_control(emu, p, cmd, data, atomic, hop); 332 else 333 gusspec_control(emu, p, cmd, data, atomic, hop); 334 return 0; 335} 336 337 338/* 339 * OSS/AWE driver specific h/w controls 340 */ 341static void 342emuspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, 343 unsigned char *event, int atomic, int hop) 344{ 345 int voice; 346 unsigned short p1; 347 short p2; 348 int i; 349 struct snd_midi_channel *chan; 350 351 voice = event[3]; 352 if (voice < 0 || voice >= port->chset.max_channels) 353 chan = NULL; 354 else 355 chan = &port->chset.channels[voice]; 356 357 p1 = *(unsigned short *) &event[4]; 358 p2 = *(short *) &event[6]; 359 360 switch (cmd) { 361 case _EMUX_OSS_SEND_EFFECT: 362 if (chan) 363 snd_emux_send_effect_oss(port, chan, p1, p2); 364 break; 365 366 case _EMUX_OSS_TERMINATE_ALL: 367 snd_emux_terminate_all(emu); 368 break; 369 370 case _EMUX_OSS_TERMINATE_CHANNEL: 371 /*snd_emux_mute_channel(emu, chan);*/ 372 break; 373 case _EMUX_OSS_RESET_CHANNEL: 374 /*snd_emux_channel_init(chset, chan);*/ 375 break; 376 377 case _EMUX_OSS_RELEASE_ALL: 378 fake_event(emu, port, voice, MIDI_CTL_ALL_NOTES_OFF, 0, atomic, hop); 379 break; 380 case _EMUX_OSS_NOTEOFF_ALL: 381 fake_event(emu, port, voice, MIDI_CTL_ALL_SOUNDS_OFF, 0, atomic, hop); 382 break; 383 384 case _EMUX_OSS_INITIAL_VOLUME: 385 if (p2) { 386 port->volume_atten = (short)p1; 387 snd_emux_update_port(port, SNDRV_EMUX_UPDATE_VOLUME); 388 } 389 break; 390 391 case _EMUX_OSS_CHN_PRESSURE: 392 if (chan) { 393 chan->midi_pressure = p1; 394 snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_FMMOD|SNDRV_EMUX_UPDATE_FM2FRQ2); 395 } 396 break; 397 398 case _EMUX_OSS_CHANNEL_MODE: 399 reset_port_mode(port, p1); 400 snd_emux_reset_port(port); 401 break; 402 403 case _EMUX_OSS_DRUM_CHANNELS: 404 port->drum_flags = *(unsigned int*)&event[4]; 405 for (i = 0; i < port->chset.max_channels; i++) { 406 chan = &port->chset.channels[i]; 407 chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0; 408 } 409 break; 410 411 case _EMUX_OSS_MISC_MODE: 412 if (p1 < EMUX_MD_END) 413 port->ctrls[p1] = p2; 414 break; 415 case _EMUX_OSS_DEBUG_MODE: 416 break; 417 418 default: 419 if (emu->ops.oss_ioctl) 420 emu->ops.oss_ioctl(emu, cmd, p1, p2); 421 break; 422 } 423} 424 425/* 426 * GUS specific h/w controls 427 */ 428 429#include <linux/ultrasound.h> 430 431static void 432gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd, 433 unsigned char *event, int atomic, int hop) 434{ 435 int voice; 436 unsigned short p1; 437 short p2; 438 int plong; 439 struct snd_midi_channel *chan; 440 441 if (port->port_mode != SNDRV_EMUX_PORT_MODE_OSS_SYNTH) 442 return; 443 if (cmd == _GUS_NUMVOICES) 444 return; 445 voice = event[3]; 446 if (voice < 0 || voice >= port->chset.max_channels) 447 return; 448 449 chan = &port->chset.channels[voice]; 450 451 p1 = *(unsigned short *) &event[4]; 452 p2 = *(short *) &event[6]; 453 plong = *(int*) &event[4]; 454 455 switch (cmd) { 456 case _GUS_VOICESAMPLE: 457 chan->midi_program = p1; 458 return; 459 460 case _GUS_VOICEBALA: 461 /* 0 to 15 --> 0 to 127 */ 462 chan->control[MIDI_CTL_MSB_PAN] = (int)p1 << 3; 463 snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PAN); 464 return; 465 466 case _GUS_VOICEVOL: 467 case _GUS_VOICEVOL2: 468 /* not supported yet */ 469 return; 470 471 case _GUS_RAMPRANGE: 472 case _GUS_RAMPRATE: 473 case _GUS_RAMPMODE: 474 case _GUS_RAMPON: 475 case _GUS_RAMPOFF: 476 /* volume ramping not supported */ 477 return; 478 479 case _GUS_VOLUME_SCALE: 480 return; 481 482 case _GUS_VOICE_POS: 483#ifdef SNDRV_EMUX_USE_RAW_EFFECT 484 snd_emux_send_effect(port, chan, EMUX_FX_SAMPLE_START, 485 (short)(plong & 0x7fff), 486 EMUX_FX_FLAG_SET); 487 snd_emux_send_effect(port, chan, EMUX_FX_COARSE_SAMPLE_START, 488 (plong >> 15) & 0xffff, 489 EMUX_FX_FLAG_SET); 490#endif 491 return; 492 } 493} 494 495 496/* 497 * send an event to midi emulation 498 */ 499static void 500fake_event(struct snd_emux *emu, struct snd_emux_port *port, int ch, int param, int val, int atomic, int hop) 501{ 502 struct snd_seq_event ev; 503 memset(&ev, 0, sizeof(ev)); 504 ev.type = SNDRV_SEQ_EVENT_CONTROLLER; 505 ev.data.control.channel = ch; 506 ev.data.control.param = param; 507 ev.data.control.value = val; 508 snd_emux_event_input(&ev, 0, port, atomic, hop); 509} 510 511#endif /* CONFIG_SND_SEQUENCER_OSS */ 512