📄 seq_oss_midi.c
字号:
/* * OSS compatible sequencer driver * * MIDI device handlers * * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de> * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "seq_oss_midi.h"#include "seq_oss_readq.h"#include "seq_oss_timer.h"#include "seq_oss_event.h"#include <sound/seq_midi_event.h>#include "../seq_lock.h"#include <linux/init.h>/* * constants */#define SNDRV_SEQ_OSS_MAX_MIDI_NAME 30/* * definition of midi device record */struct seq_oss_midi_t { int seq_device; /* device number */ int client; /* sequencer client number */ int port; /* sequencer port number */ unsigned int flags; /* port capability */ int opened; /* flag for opening */ unsigned char name[SNDRV_SEQ_OSS_MAX_MIDI_NAME]; snd_midi_event_t *coder; /* MIDI event coder */ seq_oss_devinfo_t *devinfo; /* assigned OSSseq device */ snd_use_lock_t use_lock;};/* * midi device table */static int max_midi_devs;static seq_oss_midi_t *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS];static spinlock_t register_lock = SPIN_LOCK_UNLOCKED;/* * prototypes */static seq_oss_midi_t *get_mdev(int dev);static seq_oss_midi_t *get_mididev(seq_oss_devinfo_t *dp, int dev);static int send_synth_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int dev);static int send_midi_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, seq_oss_midi_t *mdev);/* * look up the existing ports * this looks a very exhausting job. */int __initsnd_seq_oss_midi_lookup_ports(int client){ snd_seq_system_info_t sysinfo; snd_seq_client_info_t clinfo; snd_seq_port_info_t pinfo; int rc; rc = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SYSTEM_INFO, &sysinfo); if (rc < 0) return rc; memset(&clinfo, 0, sizeof(clinfo)); memset(&pinfo, 0, sizeof(pinfo)); clinfo.client = -1; while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, &clinfo) == 0) { if (clinfo.client == client) continue; /* ignore myself */ pinfo.addr.client = clinfo.client; pinfo.addr.port = -1; while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, &pinfo) == 0) snd_seq_oss_midi_check_new_port(&pinfo); } return 0;}/* */static seq_oss_midi_t *get_mdev(int dev){ seq_oss_midi_t *mdev; unsigned long flags; spin_lock_irqsave(®ister_lock, flags); mdev = midi_devs[dev]; if (mdev) snd_use_lock_use(&mdev->use_lock); spin_unlock_irqrestore(®ister_lock, flags); return mdev;}/* * look for the identical slot */static seq_oss_midi_t *find_slot(int client, int port){ int i; seq_oss_midi_t *mdev; unsigned long flags; spin_lock_irqsave(®ister_lock, flags); for (i = 0; i < max_midi_devs; i++) { mdev = midi_devs[i]; if (mdev && mdev->client == client && mdev->port == port) { /* found! */ snd_use_lock_use(&mdev->use_lock); spin_unlock_irqrestore(®ister_lock, flags); return mdev; } } spin_unlock_irqrestore(®ister_lock, flags); return NULL;}#define PERM_WRITE (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_SUBS_WRITE)#define PERM_READ (SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ)/* * register a new port if it doesn't exist yet */intsnd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo){ int i; seq_oss_midi_t *mdev; unsigned long flags; debug_printk(("check for MIDI client %d port %d\n", pinfo->addr.client, pinfo->addr.port)); /* the port must include generic midi */ if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC)) return 0; /* either read or write subscribable */ if ((pinfo->capability & PERM_WRITE) != PERM_WRITE && (pinfo->capability & PERM_READ) != PERM_READ) return 0; /* * look for the identical slot */ if ((mdev = find_slot(pinfo->addr.client, pinfo->addr.port)) != NULL) { /* already exists */ snd_use_lock_free(&mdev->use_lock); return 0; } /* * allocate midi info record */ if ((mdev = kcalloc(1, sizeof(*mdev), GFP_KERNEL)) == NULL) { snd_printk(KERN_ERR "can't malloc midi info\n"); return -ENOMEM; } /* copy the port information */ mdev->client = pinfo->addr.client; mdev->port = pinfo->addr.port; mdev->flags = pinfo->capability; mdev->opened = 0; snd_use_lock_init(&mdev->use_lock); /* copy and truncate the name of synth device */ strlcpy(mdev->name, pinfo->name, sizeof(mdev->name)); /* create MIDI coder */ if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) { snd_printk(KERN_ERR "can't malloc midi coder\n"); kfree(mdev); return -ENOMEM; } /* OSS sequencer adds running status to all sequences */ snd_midi_event_no_status(mdev->coder, 1); /* * look for en empty slot */ spin_lock_irqsave(®ister_lock, flags); for (i = 0; i < max_midi_devs; i++) { if (midi_devs[i] == NULL) break; } if (i >= max_midi_devs) { if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) { spin_unlock_irqrestore(®ister_lock, flags); snd_midi_event_free(mdev->coder); kfree(mdev); return -ENOMEM; } max_midi_devs++; } mdev->seq_device = i; midi_devs[mdev->seq_device] = mdev; spin_unlock_irqrestore(®ister_lock, flags); return 0;}/* * release the midi device if it was registered */intsnd_seq_oss_midi_check_exit_port(int client, int port){ seq_oss_midi_t *mdev; unsigned long flags; int index; if ((mdev = find_slot(client, port)) != NULL) { spin_lock_irqsave(®ister_lock, flags); midi_devs[mdev->seq_device] = NULL; spin_unlock_irqrestore(®ister_lock, flags); snd_use_lock_free(&mdev->use_lock); snd_use_lock_sync(&mdev->use_lock); if (mdev->coder) snd_midi_event_free(mdev->coder); kfree(mdev); } spin_lock_irqsave(®ister_lock, flags); for (index = max_midi_devs - 1; index >= 0; index--) { if (midi_devs[index]) break; } max_midi_devs = index + 1; spin_unlock_irqrestore(®ister_lock, flags); return 0;}/* * release the midi device if it was registered */voidsnd_seq_oss_midi_clear_all(void){ int i; seq_oss_midi_t *mdev; unsigned long flags; spin_lock_irqsave(®ister_lock, flags); for (i = 0; i < max_midi_devs; i++) { if ((mdev = midi_devs[i]) != NULL) { if (mdev->coder) snd_midi_event_free(mdev->coder); kfree(mdev); midi_devs[i] = NULL; } } max_midi_devs = 0; spin_unlock_irqrestore(®ister_lock, flags);}/* * set up midi tables */voidsnd_seq_oss_midi_setup(seq_oss_devinfo_t *dp){ dp->max_mididev = max_midi_devs;}/* * clean up midi tables */voidsnd_seq_oss_midi_cleanup(seq_oss_devinfo_t *dp){ int i; for (i = 0; i < dp->max_mididev; i++) snd_seq_oss_midi_close(dp, i); dp->max_mididev = 0;}/* * open all midi devices. ignore errors. */voidsnd_seq_oss_midi_open_all(seq_oss_devinfo_t *dp, int file_mode){ int i; for (i = 0; i < dp->max_mididev; i++) snd_seq_oss_midi_open(dp, i, file_mode);}/* * get the midi device information */static seq_oss_midi_t *get_mididev(seq_oss_devinfo_t *dp, int dev){ if (dev < 0 || dev >= dp->max_mididev) return NULL; return get_mdev(dev);}/* * open the midi device if not opened yet */intsnd_seq_oss_midi_open(seq_oss_devinfo_t *dp, int dev, int fmode){ int perm; seq_oss_midi_t *mdev; snd_seq_port_subscribe_t subs; if ((mdev = get_mididev(dp, dev)) == NULL) return -ENODEV; /* already used? */ if (mdev->opened && mdev->devinfo != dp) { snd_use_lock_free(&mdev->use_lock); return -EBUSY; } perm = 0; if (is_write_mode(fmode)) perm |= PERM_WRITE; if (is_read_mode(fmode)) perm |= PERM_READ; perm &= mdev->flags; if (perm == 0) { snd_use_lock_free(&mdev->use_lock); return -ENXIO; } /* already opened? */ if ((mdev->opened & perm) == perm) { snd_use_lock_free(&mdev->use_lock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -