/* $Id: soundmidi.c,v 1.1.1.1 2003/07/02 13:57:02 eleph Exp $ */ /* * MMPM/2 to OSS interface translation layer * * (C) 2000-2002 InnoTek Systemberatung GmbH * (C) 2000-2001 Sander van Leeuwen (sandervl@xs4all.nl) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, * USA. * */ #include #include #include #include #include #include #include #include #include #include #define LINUX #include #include #include #include "soundoss.h" int midi_port = 0; //****************************************************************************** //****************************************************************************** OSSRET OSS32_MidiOpen(ULONG deviceid, ULONG streamtype, OSSSTREAMID *pStreamId) { midihandle *pHandle; int ret, i; struct sndrv_seq_port_subscribe subs; struct sndrv_seq_client_info clientinfo; struct sndrv_seq_port_info portinfo; *pStreamId = 0; if(alsa_fops == NULL) { DebugInt3(); return OSSERR_NO_DEVICE_AVAILABLE; } pHandle = kmalloc(sizeof(midihandle), GFP_KERNEL); if(pHandle == NULL) { DebugInt3(); return OSSERR_OUT_OF_MEMORY; } memset(pHandle, 0, sizeof(midihandle)); //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; //setup pointers in file structure (used internally by ALSA) pHandle->file.f_dentry = &pHandle->d_entry; pHandle->file.f_dentry->d_inode = &pHandle->inode; switch(streamtype) { case OSS32_STREAM_MPU401_MIDIOUT: dprintf(("OSS32_STREAM_MPU401_MIDIOUT")); pHandle->file.f_mode = FMODE_WRITE; pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_RAWMIDI); pHandle->inode.i_rdev |= (CONFIG_SND_MAJOR << 8); break; case OSS32_STREAM_MPU401_MIDIIN: dprintf(("OSS32_STREAM_MPU401_MIDIIN")); pHandle->file.f_mode = FMODE_READ; pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_RAWMIDI); pHandle->inode.i_rdev |= (CONFIG_SND_MAJOR << 8); break; case OSS32_STREAM_FM_MIDIOUT: dprintf(("OSS32_STREAM_FM_MIDIOUT")); pHandle->file.f_mode = FMODE_WRITE; pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_SEQUENCER); break; case OSS32_STREAM_WAVETABLE_MIDIOUT: dprintf(("OSS32_STREAM_WAVETABLE_MIDIOUT: TODO")); pHandle->file.f_mode = FMODE_WRITE; pHandle->inode.i_rdev = SNDRV_MINOR(deviceid, SNDRV_MINOR_SEQUENCER); kfree(pHandle); return OSSERR_INVALID_PARAMETER; break; default: DebugInt3(); kfree(pHandle); return OSSERR_INVALID_PARAMETER; } #if 1 ret = alsa_fops->open(&pHandle->inode, &pHandle->file); if(ret) { dprintf(("Midi Open %d failed with error %d", streamtype, ret)); kfree(pHandle); return UNIXToOSSError(ret); } pHandle->magic = MAGIC_MIDI_ALSA32; *pStreamId = (ULONG)pHandle; pHandle->state |= MIDISTATE_OPENED; printk("Opened MIDI %x\n",(ULONG)pHandle); if(streamtype == OSS32_STREAM_FM_MIDIOUT) { //get the client id ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_SEQ_IOCTL_CLIENT_ID, (ULONG)&pHandle->clientid); if(ret) { dprintf(("Get client id failed with error %d", ret)); kfree(pHandle); return UNIXToOSSError(ret); } //find the FM device for(i=64;i<64+((deviceid+1)<<3);i++) { memset((PVOID)__Stack32ToFlat(&clientinfo), 0, sizeof(clientinfo)); clientinfo.client = i; clientinfo.type = KERNEL_CLIENT; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, (ULONG)__Stack32ToFlat(&clientinfo)); if(ret) { continue; } if(!strcmp(clientinfo.name, "OPL3 FM synth")) { //found the FM synth device break; } } if(i == 64+((deviceid+1)<<3)) { dprintf(("Couldn't find OPL3 device")); ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file); kfree(pHandle); *pStreamId = 0; return OSSERR_NO_DEVICE_AVAILABLE; } pHandle->destclient = i; pHandle->destport = 0; //create client port memset(&portinfo, 0, sizeof(portinfo)); strcpy(portinfo.name, "Unamed port"); portinfo.addr.client = pHandle->clientid; portinfo.flags = SNDRV_SEQ_PORT_TYPE_APPLICATION; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_SEQ_IOCTL_CREATE_PORT, (ULONG)__Stack32ToFlat(&portinfo)); if(ret) { dprintf(("subscribe error %d", ret)); kfree(pHandle); return UNIXToOSSError(ret); } pHandle->clientport = portinfo.addr.port; pHandle->state |= MIDISTATE_PORTCREATED; //subscribe to FM device port memset(&subs, 0, sizeof(subs)); subs.dest.client = pHandle->destclient; subs.dest.port = pHandle->destport; subs.sender.client = pHandle->clientid; subs.sender.port = pHandle->clientport; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, (ULONG)__Stack32ToFlat(&subs)); if(ret) { dprintf(("subscribe error %d", ret)); kfree(pHandle); return UNIXToOSSError(ret); } pHandle->state |= MIDISTATE_SUBSCRIBED; //Load FM instruments (only done once) OSS32_FMMidiLoadInstruments((ULONG)pHandle); }//if FM #endif return OSSERR_SUCCESS; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MidiClose(OSSSTREAMID streamid) { midihandle *pHandle = (midihandle *)streamid; int ret; if(pHandle == NULL || pHandle->magic != MAGIC_MIDI_ALSA32) { DebugInt3(); return OSSERR_INVALID_STREAMID; } printk("Closing MIDI %x\n",(ULONG)streamid); //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; //unsubscribe if(pHandle->state & MIDISTATE_SUBSCRIBED) { struct sndrv_seq_port_subscribe subs; memset(&subs, 0, sizeof(subs)); subs.dest.client = pHandle->destclient; subs.dest.port = pHandle->destport; subs.sender.client = pHandle->clientid; subs.sender.port = pHandle->clientport; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, (ULONG)__Stack32ToFlat(&subs)); if(ret) { dprintf(("unsubscribe error %d", ret)); DebugInt3(); } } //delete port if(pHandle->state & MIDISTATE_SUBSCRIBED) { struct sndrv_seq_port_info portinfo; memset(&portinfo, 0, sizeof(portinfo)); strcpy(portinfo.name, "Unamed port"); portinfo.addr.client = pHandle->clientid; portinfo.addr.port = pHandle->clientport; ret = pHandle->file.f_op->ioctl(&pHandle->inode, &pHandle->file, SNDRV_SEQ_IOCTL_DELETE_PORT, (ULONG)__Stack32ToFlat(&portinfo)); if(ret) { dprintf(("delete port error %d", ret)); DebugInt3(); } } //and release device ret = pHandle->file.f_op->release(&pHandle->inode, &pHandle->file); kfree(pHandle); //free handle data if(ret) { DebugInt3(); return UNIXToOSSError(ret); } return OSSERR_SUCCESS; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MidiWrite(OSSSTREAMID streamid, ULONG midiByte) { printk("MIDI write %x\n",(ULONG)streamid); return OSSERR_INVALID_STREAMID; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MidiRead(OSSSTREAMID streamid, char *buffer, ULONG bufsize, ULONG *pTransferred) { midihandle *pHandle = (midihandle *)streamid; int ret; if(pHandle == NULL || pHandle->magic != MAGIC_MIDI_ALSA32) { DebugInt3(); return OSSERR_INVALID_STREAMID; } //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; //and release device ret = pHandle->file.f_op->read(&pHandle->file,(char*)buffer, bufsize, &pHandle->file.f_pos); kfree(pHandle); //free handle data if (ret > 0) { printk("MIDI read %i bytes from %x. first byte is: %x\n",ret, (ULONG)streamid, (char*)buffer[0]); *pTransferred = ret; return OSSERR_SUCCESS; } return UNIXToOSSError(ret); } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MidiQueryCaps(OSSSTREAMID streamid, POSS32_MIDICAPS pCaps) { printk("MIDI query caps %x\n",(ULONG)streamid); return OSSERR_INVALID_STREAMID; } //****************************************************************************** //****************************************************************************** OSSRET OSS32_MidiCommand(OSSSTREAMID streamid, ULONG Cmd, BYTE channel, BYTE param1, BYTE param2) { midihandle *pHandle = (midihandle *)streamid; int ret; LONG transferred; struct sndrv_seq_event fmevent; if(pHandle == NULL || pHandle->magic != MAGIC_MIDI_ALSA32) { DebugInt3(); return OSSERR_INVALID_STREAMID; } printk("MIDI command %x\n",(ULONG)streamid); //set operation to non-blocking pHandle->file.f_flags = O_NONBLOCK; memset((PVOID)__Stack32ToFlat(&fmevent), 0, sizeof(fmevent)); switch(Cmd) { case IDC32_MIDI_NOTEON: snd_seq_ev_set_noteon((&fmevent), channel, param1, param2); break; case IDC32_MIDI_NOTEOFF: snd_seq_ev_set_noteoff((&fmevent), channel, param1, param2); break; case IDC32_MIDI_KEY_PRESSURE: snd_seq_ev_set_keypress((&fmevent), channel, param1, param2); break; case IDC32_MIDI_CONTROL_CHANGE: snd_seq_ev_set_controller((&fmevent), channel, param1, param2); break; case IDC32_MIDI_PROGRAM_CHANGE: snd_seq_ev_set_pgmchange((&fmevent), channel, param1); break; case IDC32_MIDI_CHANNEL_PRESSURE: snd_seq_ev_set_chanpress((&fmevent), channel, param1); break; case IDC32_MIDI_PITCH_BEND: snd_seq_ev_set_pitchbend((&fmevent), channel, param1); break; } fmevent.tag = 0; fmevent.queue = SNDRV_SEQ_QUEUE_DIRECT; fmevent.source.client = pHandle->clientid; fmevent.source.port = pHandle->clientport; fmevent.dest.client = pHandle->destclient; fmevent.dest.port = pHandle->destport; transferred = pHandle->file.f_op->write(&pHandle->file, (char *)__Stack32ToFlat(&fmevent), sizeof(fmevent), &pHandle->file.f_pos); if(transferred < 0) { dprintf(("OSS32_MidiNoteOn failed!!")); DebugInt3(); return UNIXToOSSError(transferred); } return OSSERR_SUCCESS; } //****************************************************************************** //******************************************************************************