aboutsummaryrefslogtreecommitdiff
path: root/sound/core/seq/oss
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/core/seq/oss
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'sound/core/seq/oss')
-rw-r--r--sound/core/seq/oss/Makefile10
-rw-r--r--sound/core/seq/oss/seq_oss.c317
-rw-r--r--sound/core/seq/oss/seq_oss_device.h198
-rw-r--r--sound/core/seq/oss/seq_oss_event.c447
-rw-r--r--sound/core/seq/oss/seq_oss_event.h112
-rw-r--r--sound/core/seq/oss/seq_oss_init.c555
-rw-r--r--sound/core/seq/oss/seq_oss_ioctl.c209
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c710
-rw-r--r--sound/core/seq/oss/seq_oss_midi.h49
-rw-r--r--sound/core/seq/oss/seq_oss_readq.c234
-rw-r--r--sound/core/seq/oss/seq_oss_readq.h56
-rw-r--r--sound/core/seq/oss/seq_oss_rw.c216
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c659
-rw-r--r--sound/core/seq/oss/seq_oss_synth.h49
-rw-r--r--sound/core/seq/oss/seq_oss_timer.c283
-rw-r--r--sound/core/seq/oss/seq_oss_timer.h70
-rw-r--r--sound/core/seq/oss/seq_oss_writeq.c170
-rw-r--r--sound/core/seq/oss/seq_oss_writeq.h50
18 files changed, 4394 insertions, 0 deletions
diff --git a/sound/core/seq/oss/Makefile b/sound/core/seq/oss/Makefile
new file mode 100644
index 00000000000..a37ddedf710
--- /dev/null
+++ b/sound/core/seq/oss/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for ALSA
+# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-seq-oss-objs := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \
+ seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \
+ seq_oss_midi.o seq_oss_readq.o seq_oss_writeq.o
+
+obj-$(CONFIG_SND_SEQUENCER) += snd-seq-oss.o
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
new file mode 100644
index 00000000000..4c0558c0a8b
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss.c
@@ -0,0 +1,317 @@
+/*
+ * OSS compatible sequencer driver
+ *
+ * registration of device and proc
+ *
+ * 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 <sound/driver.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include <sound/minors.h>
+#include <sound/initval.h>
+#include "seq_oss_device.h"
+#include "seq_oss_synth.h"
+
+/*
+ * module option
+ */
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+MODULE_DESCRIPTION("OSS-compatible sequencer module");
+MODULE_LICENSE("GPL");
+/* Takashi says this is really only for sound-service-0-, but this is OK. */
+MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_SEQUENCER);
+MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC);
+
+#ifdef SNDRV_SEQ_OSS_DEBUG
+module_param(seq_oss_debug, int, 0644);
+MODULE_PARM_DESC(seq_oss_debug, "debug option");
+int seq_oss_debug = 0;
+#endif
+
+
+/*
+ * prototypes
+ */
+static int register_device(void);
+static void unregister_device(void);
+static int register_proc(void);
+static void unregister_proc(void);
+
+static int odev_open(struct inode *inode, struct file *file);
+static int odev_release(struct inode *inode, struct file *file);
+static ssize_t odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset);
+static ssize_t odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset);
+static long odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+static unsigned int odev_poll(struct file *file, poll_table * wait);
+#ifdef CONFIG_PROC_FS
+static void info_read(snd_info_entry_t *entry, snd_info_buffer_t *buf);
+#endif
+
+
+/*
+ * module interface
+ */
+
+static int __init alsa_seq_oss_init(void)
+{
+ int rc;
+ static snd_seq_dev_ops_t ops = {
+ snd_seq_oss_synth_register,
+ snd_seq_oss_synth_unregister,
+ };
+
+ snd_seq_autoload_lock();
+ if ((rc = register_device()) < 0)
+ goto error;
+ if ((rc = register_proc()) < 0) {
+ unregister_device();
+ goto error;
+ }
+ if ((rc = snd_seq_oss_create_client()) < 0) {
+ unregister_proc();
+ unregister_device();
+ goto error;
+ }
+
+ if ((rc = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OSS, &ops,
+ sizeof(snd_seq_oss_reg_t))) < 0) {
+ snd_seq_oss_delete_client();
+ unregister_proc();
+ unregister_device();
+ goto error;
+ }
+
+ /* success */
+ snd_seq_oss_synth_init();
+
+ error:
+ snd_seq_autoload_unlock();
+ return rc;
+}
+
+static void __exit alsa_seq_oss_exit(void)
+{
+ snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OSS);
+ snd_seq_oss_delete_client();
+ unregister_proc();
+ unregister_device();
+}
+
+module_init(alsa_seq_oss_init)
+module_exit(alsa_seq_oss_exit)
+
+/*
+ * ALSA minor device interface
+ */
+
+static DECLARE_MUTEX(register_mutex);
+
+static int
+odev_open(struct inode *inode, struct file *file)
+{
+ int level, rc;
+
+ if (iminor(inode) == SNDRV_MINOR_OSS_MUSIC)
+ level = SNDRV_SEQ_OSS_MODE_MUSIC;
+ else
+ level = SNDRV_SEQ_OSS_MODE_SYNTH;
+
+ down(&register_mutex);
+ rc = snd_seq_oss_open(file, level);
+ up(&register_mutex);
+
+ return rc;
+}
+
+static int
+odev_release(struct inode *inode, struct file *file)
+{
+ seq_oss_devinfo_t *dp;
+
+ if ((dp = file->private_data) == NULL)
+ return 0;
+
+ snd_seq_oss_drain_write(dp);
+
+ down(&register_mutex);
+ snd_seq_oss_release(dp);
+ up(&register_mutex);
+
+ return 0;
+}
+
+static ssize_t
+odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
+{
+ seq_oss_devinfo_t *dp;
+ dp = file->private_data;
+ snd_assert(dp != NULL, return -EIO);
+ return snd_seq_oss_read(dp, buf, count);
+}
+
+
+static ssize_t
+odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
+{
+ seq_oss_devinfo_t *dp;
+ dp = file->private_data;
+ snd_assert(dp != NULL, return -EIO);
+ return snd_seq_oss_write(dp, buf, count, file);
+}
+
+static long
+odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ seq_oss_devinfo_t *dp;
+ dp = file->private_data;
+ snd_assert(dp != NULL, return -EIO);
+ return snd_seq_oss_ioctl(dp, cmd, arg);
+}
+
+#ifdef CONFIG_COMPAT
+#define odev_ioctl_compat odev_ioctl
+#else
+#define odev_ioctl_compat NULL
+#endif
+
+static unsigned int
+odev_poll(struct file *file, poll_table * wait)
+{
+ seq_oss_devinfo_t *dp;
+ dp = file->private_data;
+ snd_assert(dp != NULL, return 0);
+ return snd_seq_oss_poll(dp, file, wait);
+}
+
+/*
+ * registration of sequencer minor device
+ */
+
+static struct file_operations seq_oss_f_ops =
+{
+ .owner = THIS_MODULE,
+ .read = odev_read,
+ .write = odev_write,
+ .open = odev_open,
+ .release = odev_release,
+ .poll = odev_poll,
+ .unlocked_ioctl = odev_ioctl,
+ .compat_ioctl = odev_ioctl_compat,
+};
+
+static snd_minor_t seq_oss_reg = {
+ .comment = "sequencer",
+ .f_ops = &seq_oss_f_ops,
+};
+
+static int __init
+register_device(void)
+{
+ int rc;
+
+ down(&register_mutex);
+ if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
+ NULL, 0,
+ &seq_oss_reg,
+ SNDRV_SEQ_OSS_DEVNAME)) < 0) {
+ snd_printk(KERN_ERR "can't register device seq\n");
+ up(&register_mutex);
+ return rc;
+ }
+ if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
+ NULL, 0,
+ &seq_oss_reg,
+ SNDRV_SEQ_OSS_DEVNAME)) < 0) {
+ snd_printk(KERN_ERR "can't register device music\n");
+ snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
+ up(&register_mutex);
+ return rc;
+ }
+ debug_printk(("device registered\n"));
+ up(&register_mutex);
+ return 0;
+}
+
+static void
+unregister_device(void)
+{
+ down(&register_mutex);
+ debug_printk(("device unregistered\n"));
+ if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0)
+ snd_printk(KERN_ERR "error unregister device music\n");
+ if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0)
+ snd_printk(KERN_ERR "error unregister device seq\n");
+ up(&register_mutex);
+}
+
+/*
+ * /proc interface
+ */
+
+#ifdef CONFIG_PROC_FS
+
+static snd_info_entry_t *info_entry;
+
+static void
+info_read(snd_info_entry_t *entry, snd_info_buffer_t *buf)
+{
+ down(&register_mutex);
+ snd_iprintf(buf, "OSS sequencer emulation version %s\n", SNDRV_SEQ_OSS_VERSION_STR);
+ snd_seq_oss_system_info_read(buf);
+ snd_seq_oss_synth_info_read(buf);
+ snd_seq_oss_midi_info_read(buf);
+ up(&register_mutex);
+}
+
+#endif /* CONFIG_PROC_FS */
+
+static int __init
+register_proc(void)
+{
+#ifdef CONFIG_PROC_FS
+ snd_info_entry_t *entry;
+
+ entry = snd_info_create_module_entry(THIS_MODULE, SNDRV_SEQ_OSS_PROCNAME, snd_seq_root);
+ if (entry == NULL)
+ return -ENOMEM;
+
+ entry->content = SNDRV_INFO_CONTENT_TEXT;
+ entry->private_data = NULL;
+ entry->c.text.read_size = 1024;
+ entry->c.text.read = info_read;
+ if (snd_info_register(entry) < 0) {
+ snd_info_free_entry(entry);
+ return -ENOMEM;
+ }
+ info_entry = entry;
+#endif
+ return 0;
+}
+
+static void
+unregister_proc(void)
+{
+#ifdef CONFIG_PROC_FS
+ if (info_entry)
+ snd_info_unregister(info_entry);
+ info_entry = NULL;
+#endif
+}
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
new file mode 100644
index 00000000000..da23c4db8dd
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_device.h
@@ -0,0 +1,198 @@
+/*
+ * OSS compatible sequencer driver
+ *
+ * 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
+ */
+
+#ifndef __SEQ_OSS_DEVICE_H
+#define __SEQ_OSS_DEVICE_H
+
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <sound/core.h>
+#include <sound/seq_oss.h>
+#include <sound/rawmidi.h>
+#include <sound/seq_kernel.h>
+#include <sound/info.h>
+
+/* enable debug print */
+#define SNDRV_SEQ_OSS_DEBUG
+
+/* max. applications */
+#define SNDRV_SEQ_OSS_MAX_CLIENTS 16
+#define SNDRV_SEQ_OSS_MAX_SYNTH_DEVS 16
+#define SNDRV_SEQ_OSS_MAX_MIDI_DEVS 32
+
+/* version */
+#define SNDRV_SEQ_OSS_MAJOR_VERSION 0
+#define SNDRV_SEQ_OSS_MINOR_VERSION 1
+#define SNDRV_SEQ_OSS_TINY_VERSION 8
+#define SNDRV_SEQ_OSS_VERSION_STR "0.1.8"
+
+/* device and proc interface name */
+#define SNDRV_SEQ_OSS_DEVNAME "seq_oss"
+#define SNDRV_SEQ_OSS_PROCNAME "oss"
+
+
+/*
+ * type definitions
+ */
+
+typedef struct seq_oss_devinfo_t seq_oss_devinfo_t;
+typedef struct seq_oss_writeq_t seq_oss_writeq_t;
+typedef struct seq_oss_readq_t seq_oss_readq_t;
+typedef struct seq_oss_timer_t seq_oss_timer_t;
+typedef struct seq_oss_synthinfo_t seq_oss_synthinfo_t;
+typedef struct seq_oss_synth_sysex_t seq_oss_synth_sysex_t;
+typedef struct seq_oss_chinfo_t seq_oss_chinfo_t;
+typedef unsigned int reltime_t;
+typedef unsigned int abstime_t;
+typedef union evrec_t evrec_t;
+
+
+/*
+ * synthesizer channel information
+ */
+struct seq_oss_chinfo_t {
+ int note, vel;
+};
+
+/*
+ * synthesizer information
+ */
+struct seq_oss_synthinfo_t {
+ snd_seq_oss_arg_t arg;
+ seq_oss_chinfo_t *ch;
+ seq_oss_synth_sysex_t *sysex;
+ int nr_voices;
+ int opened;
+ int is_midi;
+ int midi_mapped;
+};
+
+
+/*
+ * sequencer client information
+ */
+
+struct seq_oss_devinfo_t {
+
+ int index; /* application index */
+ int cseq; /* sequencer client number */
+ int port; /* sequencer port number */
+ int queue; /* sequencer queue number */
+
+ snd_seq_addr_t addr; /* address of this device */
+
+ int seq_mode; /* sequencer mode */
+ int file_mode; /* file access */
+
+ /* midi device table */
+ int max_mididev;
+
+ /* synth device table */
+ int max_synthdev;
+ seq_oss_synthinfo_t synths[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS];
+ int synth_opened;
+
+ /* output queue */
+ seq_oss_writeq_t *writeq;
+
+ /* midi input queue */
+ seq_oss_readq_t *readq;
+
+ /* timer */
+ seq_oss_timer_t *timer;
+};
+
+
+/*
+ * function prototypes
+ */
+
+/* create/delete OSS sequencer client */
+int snd_seq_oss_create_client(void);
+int snd_seq_oss_delete_client(void);
+
+/* device file interface */
+int snd_seq_oss_open(struct file *file, int level);
+void snd_seq_oss_release(seq_oss_devinfo_t *dp);
+int snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long arg);
+int snd_seq_oss_read(seq_oss_devinfo_t *dev, char __user *buf, int count);
+int snd_seq_oss_write(seq_oss_devinfo_t *dp, const char __user *buf, int count, struct file *opt);
+unsigned int snd_seq_oss_poll(seq_oss_devinfo_t *dp, struct file *file, poll_table * wait);
+
+void snd_seq_oss_reset(seq_oss_devinfo_t *dp);
+void snd_seq_oss_drain_write(seq_oss_devinfo_t *dp);
+
+/* */
+void snd_seq_oss_process_queue(seq_oss_devinfo_t *dp, abstime_t time);
+
+
+/* proc interface */
+void snd_seq_oss_system_info_read(snd_info_buffer_t *buf);
+void snd_seq_oss_midi_info_read(snd_info_buffer_t *buf);
+void snd_seq_oss_synth_info_read(snd_info_buffer_t *buf);
+void snd_seq_oss_readq_info_read(seq_oss_readq_t *q, snd_info_buffer_t *buf);
+
+/* file mode macros */
+#define is_read_mode(mode) ((mode) & SNDRV_SEQ_OSS_FILE_READ)
+#define is_write_mode(mode) ((mode) & SNDRV_SEQ_OSS_FILE_WRITE)
+#define is_nonblock_mode(mode) ((mode) & SNDRV_SEQ_OSS_FILE_NONBLOCK)
+
+/* dispatch event */
+inline static int
+snd_seq_oss_dispatch(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int atomic, int hop)
+{
+ return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop);
+}
+
+/* ioctl */
+inline static int
+snd_seq_oss_control(seq_oss_devinfo_t *dp, unsigned int type, void *arg)
+{
+ return snd_seq_kernel_client_ctl(dp->cseq, type, arg);
+}
+
+/* fill the addresses in header */
+inline static void
+snd_seq_oss_fill_addr(seq_oss_devinfo_t *dp, snd_seq_event_t *ev,
+ int dest_client, int dest_port)
+{
+ ev->queue = dp->queue;
+ ev->source = dp->addr;
+ ev->dest.client = dest_client;
+ ev->dest.port = dest_port;
+}
+
+
+/* misc. functions for proc interface */
+char *enabled_str(int bool);
+
+
+/* for debug */
+#ifdef SNDRV_SEQ_OSS_DEBUG
+extern int seq_oss_debug;
+#define debug_printk(x) do { if (seq_oss_debug > 0) snd_printk x; } while (0)
+#else
+#define debug_printk(x) /**/
+#endif
+
+#endif /* __SEQ_OSS_DEVICE_H */
diff --git a/sound/core/seq/oss/seq_oss_event.c b/sound/core/seq/oss/seq_oss_event.c
new file mode 100644
index 00000000000..58e52ddd292
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_event.c
@@ -0,0 +1,447 @@
+/*
+ * OSS compatible sequencer driver
+ *
+ * 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_device.h"
+#include "seq_oss_synth.h"
+#include "seq_oss_midi.h"
+#include "seq_oss_event.h"
+#include "seq_oss_timer.h"
+#include <sound/seq_oss_legacy.h>
+#include "seq_oss_readq.h"
+#include "seq_oss_writeq.h"
+
+
+/*
+ * prototypes
+ */
+static int extended_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev);
+static int chn_voice_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
+static int chn_common_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
+static int timing_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
+static int local_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
+static int old_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev);
+static int note_on_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev);
+static int note_off_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev);
+static int set_note_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int note, int vel, snd_seq_event_t *ev);
+static int set_control_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int param, int val, snd_seq_event_t *ev);
+static int set_echo_event(seq_oss_devinfo_t *dp, evrec_t *rec, snd_seq_event_t *ev);
+
+
+/*
+ * convert an OSS event to ALSA event
+ * return 0 : enqueued
+ * non-zero : invalid - ignored
+ */
+
+int
+snd_seq_oss_process_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+{
+ switch (q->s.code) {
+ case SEQ_EXTENDED:
+ return extended_event(dp, q, ev);
+
+ case EV_CHN_VOICE:
+ return chn_voice_event(dp, q, ev);
+
+ case EV_CHN_COMMON:
+ return chn_common_event(dp, q, ev);
+
+ case EV_TIMING:
+ return timing_event(dp, q, ev);
+
+ case EV_SEQ_LOCAL:
+ return local_event(dp, q, ev);
+
+ case EV_SYSEX:
+ return snd_seq_oss_synth_sysex(dp, q->x.dev, q->x.buf, ev);
+
+ case SEQ_MIDIPUTC:
+ if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
+ return -EINVAL;
+ /* put a midi byte */
+ if (! is_write_mode(dp->file_mode))
+ break;
+ if (snd_seq_oss_midi_open(dp, q->s.dev, SNDRV_SEQ_OSS_FILE_WRITE))
+ break;
+ if (snd_seq_oss_midi_filemode(dp, q->s.dev) & SNDRV_SEQ_OSS_FILE_WRITE)
+ return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev);
+ break;
+
+ case SEQ_ECHO:
+ if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
+ return -EINVAL;
+ return set_echo_event(dp, q, ev);
+
+ case SEQ_PRIVATE:
+ if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
+ return -EINVAL;
+ return snd_seq_oss_synth_raw_event(dp, q->c[1], q->c, ev);
+
+ default:
+ if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
+ return -EINVAL;
+ return old_event(dp, q, ev);
+ }
+ return -EINVAL;
+}
+
+/* old type events: mode1 only */
+static int
+old_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+{
+ switch (q->s.code) {
+ case SEQ_NOTEOFF:
+ return note_off_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev);
+
+ case SEQ_NOTEON:
+ return note_on_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev);
+
+ case SEQ_WAIT:
+ /* skip */
+ break;
+
+ case SEQ_PGMCHANGE:
+ return set_control_event(dp, 0, SNDRV_SEQ_EVENT_PGMCHANGE,
+ q->n.chn, 0, q->n.note, ev);
+
+ case SEQ_SYNCTIMER:
+ return snd_seq_oss_timer_reset(dp->timer);
+ }
+
+ return -EINVAL;
+}
+
+/* 8bytes extended event: mode1 only */
+static int
+extended_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+{
+ int val;
+
+ switch (q->e.cmd) {
+ case SEQ_NOTEOFF:
+ return note_off_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev);
+
+ case SEQ_NOTEON:
+ return note_on_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev);
+
+ case SEQ_PGMCHANGE:
+ return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_PGMCHANGE,
+ q->e.chn, 0, q->e.p1, ev);
+
+ case SEQ_AFTERTOUCH:
+ return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CHANPRESS,
+ q->e.chn, 0, q->e.p1, ev);
+
+ case SEQ_BALANCE:
+ /* convert -128:127 to 0:127 */
+ val = (char)q->e.p1;
+ val = (val + 128) / 2;
+ return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CONTROLLER,
+ q->e.chn, CTL_PAN, val, ev);
+
+ case SEQ_CONTROLLER:
+ val = ((short)q->e.p3 << 8) | (short)q->e.p2;
+ switch (q->e.p1) {
+ case CTRL_PITCH_BENDER: /* SEQ1 V2 control */
+ /* -0x2000:0x1fff */
+ return set_control_event(dp, q->e.dev,
+ SNDRV_SEQ_EVENT_PITCHBEND,
+ q->e.chn, 0, val, ev);
+ case CTRL_PITCH_BENDER_RANGE:
+ /* conversion: 100/semitone -> 128/semitone */
+ return set_control_event(dp, q->e.dev,
+ SNDRV_SEQ_EVENT_REGPARAM,
+ q->e.chn, 0, val*128/100, ev);
+ default:
+ return set_control_event(dp, q->e.dev,
+ SNDRV_SEQ_EVENT_CONTROL14,
+ q->e.chn, q->e.p1, val, ev);
+ }
+
+ case SEQ_VOLMODE:
+ return snd_seq_oss_synth_raw_event(dp, q->e.dev, q->c, ev);
+
+ }
+ return -EINVAL;
+}
+
+/* channel voice events: mode1 and 2 */
+static int
+chn_voice_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+{
+ if (q->v.chn >= 32)
+ return -EINVAL;
+ switch (q->v.cmd) {
+ case MIDI_NOTEON:
+ return note_on_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev);
+
+ case MIDI_NOTEOFF:
+ return note_off_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev);
+
+ case MIDI_KEY_PRESSURE:
+ return set_note_event(dp, q->v.dev, SNDRV_SEQ_EVENT_KEYPRESS,
+ q->v.chn, q->v.note, q->v.parm, ev);
+
+ }
+ return -EINVAL;
+}
+
+/* channel common events: mode1 and 2 */
+static int
+chn_common_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+{
+ if (q->l.chn >= 32)
+ return -EINVAL;
+ switch (q->l.cmd) {
+ case MIDI_PGM_CHANGE:
+ return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PGMCHANGE,
+ q->l.chn, 0, q->l.p1, ev);
+
+ case MIDI_CTL_CHANGE:
+ return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CONTROLLER,
+ q->l.chn, q->l.p1, q->l.val, ev);
+
+ case MIDI_PITCH_BEND:
+ /* conversion: 0:0x3fff -> -0x2000:0x1fff */
+ return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PITCHBEND,
+ q->l.chn, 0, q->l.val - 8192, ev);
+
+ case MIDI_CHN_PRESSURE:
+ return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CHANPRESS,
+ q->l.chn, 0, q->l.val, ev);
+ }
+ return -EINVAL;
+}
+
+/* timer events: mode1 and mode2 */
+static int
+timing_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+{
+ switch (q->t.cmd) {
+ case TMR_ECHO:
+ if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
+ return set_echo_event(dp, q, ev);
+ else {
+ evrec_t tmp;
+ memset(&tmp, 0, sizeof(tmp));
+ /* XXX: only for little-endian! */
+ tmp.echo = (q->t.time << 8) | SEQ_ECHO;
+ return set_echo_event(dp, &tmp, ev);
+ }
+
+ case TMR_STOP:
+ if (dp->seq_mode)
+ return snd_seq_oss_timer_stop(dp->timer);
+ return 0;
+
+ case TMR_CONTINUE:
+ if (dp->seq_mode)
+ return snd_seq_oss_timer_continue(dp->timer);
+ return 0;
+
+ case TMR_TEMPO:
+ if (dp->seq_mode)
+ return snd_seq_oss_timer_tempo(dp->timer, q->t.time);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/* local events: mode1 and 2 */
+static int
+local_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
+{
+ return -EINVAL;
+}
+
+/*
+ * process note-on event for OSS synth
+ * three different modes are available:
+ * - SNDRV_SEQ_OSS_PROCESS_EVENTS (for one-voice per channel mode)
+ * Accept note 255 as volume change.
+ * - SNDRV_SEQ_OSS_PASS_EVENTS
+ * Pass all events to lowlevel driver anyway
+ * - SNDRV_SEQ_OSS_PROCESS_KEYPRESS (mostly for Emu8000)
+ * Use key-pressure if note >= 128
+ */
+static int
+note_on_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev)
+{
+ seq_oss_synthinfo_t *info = &dp->synths[dev];
+ switch (info->arg.event_passing) {
+ case SNDRV_SEQ_OSS_PROCESS_EVENTS:
+ if (! info->ch || ch < 0 || ch >= info->nr_voices) {
+ /* pass directly */
+ return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
+ }
+
+ if (note == 255 && info->ch[ch].note >= 0) {
+ /* volume control */
+ int type;
+ //if (! vel)
+ /* set volume to zero -- note off */
+ // type = SNDRV_SEQ_EVENT_NOTEOFF;
+ //else
+ if (info->ch[ch].vel)
+ /* sample already started -- volume change */
+ type = SNDRV_SEQ_EVENT_KEYPRESS;
+ else
+ /* sample not started -- start now */
+ type = SNDRV_SEQ_EVENT_NOTEON;
+ info->ch[ch].vel = vel;
+ return set_note_event(dp, dev, type, ch, info->ch[ch].note, vel, ev);
+ } else if (note >= 128)
+ return -EINVAL; /* invalid */
+
+ if (note != info->ch[ch].note && info->ch[ch].note >= 0)
+ /* note changed - note off at beginning */
+ set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, info->ch[ch].note, 0, ev);
+ /* set current status */
+ info->ch[ch].note = note;
+ info->ch[ch].vel = vel;
+ if (vel) /* non-zero velocity - start the note now */
+ return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
+ return -EINVAL;
+
+ case SNDRV_SEQ_OSS_PASS_EVENTS:
+ /* pass the event anyway */
+ return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
+
+ case SNDRV_SEQ_OSS_PROCESS_KEYPRESS:
+ if (note >= 128) /* key pressure: shifted by 128 */
+ return set_note_event(dp, dev, SNDRV_SEQ_EVENT_KEYPRESS, ch, note - 128, vel, ev);
+ else /* normal note-on event */
+ return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
+ }
+ return -EINVAL;
+}
+
+/*
+ * process note-off event for OSS synth
+ */
+static int
+note_off_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev)
+{
+ seq_oss_synthinfo_t *info = &dp->synths[dev];
+ switch (info->arg.event_passing) {
+ case SNDRV_SEQ_OSS_PROCESS_EVENTS:
+ if (! info->ch || ch < 0 || ch >= info->nr_voices) {
+ /* pass directly */
+ return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
+ }
+
+ if (info->ch[ch].note >= 0) {
+ note = info->ch[ch].note;
+ info->ch[ch].vel = 0;
+ info->ch[ch].note = -1;
+ return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev);
+ }
+ return -EINVAL; /* invalid */
+
+ case SNDRV_SEQ_OSS_PASS_EVENTS:
+ case SNDRV_SEQ_OSS_PROCESS_KEYPRESS:
+ /* pass the event anyway */
+ return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev);
+
+ }
+ return -EINVAL;
+}
+
+/*
+ * create a note event
+ */
+static int
+set_note_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int note, int vel, snd_seq_event_t *ev)
+{
+ if (! snd_seq_oss_synth_is_valid(dp, dev))
+ return -ENXIO;
+
+ ev->type = type;
+ snd_seq_oss_synth_addr(dp, dev, ev);
+ ev->data.note.channel = ch;
+ ev->data.note.note = note;
+ ev->data.note.velocity = vel;
+
+ return 0;
+}
+
+/*
+ * create a control event
+ */
+static int
+set_control_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int param, int val, snd_seq_event_t *ev)
+{
+ if (! snd_seq_oss_synth_is_valid(dp, dev))
+ return -ENXIO;
+
+ ev->type = type;
+ snd_seq_oss_synth_addr(dp, dev, ev);
+ ev->data.control.channel = ch;
+ ev->data.control.param = param;
+ ev->data.control.value = val;
+
+ return 0;
+}
+
+/*
+ * create an echo event
+ */
+static int
+set_echo_event(seq_oss_devinfo_t *dp, evrec_t *rec, snd_seq_event_t *ev)
+{
+ ev->type = SNDRV_SEQ_EVENT_ECHO;
+ /* echo back to itself */
+ snd_seq_oss_fill_addr(dp, ev, dp->addr.client, dp->addr.port);
+ memcpy(&ev->data, rec, LONG_EVENT_SIZE);
+ return 0;
+}
+
+/*
+ * event input callback from ALSA sequencer:
+ * the echo event is processed here.
+ */
+int
+snd_seq_oss_event_input(snd_seq_event_t *ev, int direct, void *private_data,
+ int atomic, int hop)
+{
+ seq_oss_devinfo_t *dp = (seq_oss_devinfo_t *)private_data;
+ evrec_t *rec;
+
+ if (ev->type != SNDRV_SEQ_EVENT_ECHO)
+ return snd_seq_oss_midi_input(ev, direct, private_data);
+
+ if (ev->source.client != dp->cseq)
+ return 0; /* ignored */
+
+ rec = (evrec_t*)&ev->data;
+ if (rec->s.code == SEQ_SYNCTIMER) {
+ /* sync echo back */
+ snd_seq_oss_writeq_wakeup(dp->writeq, rec->t.time);
+
+ } else {
+ /* echo back event */
+ if (dp->readq == NULL)
+ return 0;
+ snd_seq_oss_readq_put_event(dp->readq, rec);
+ }
+ return 0;
+}
+
diff --git a/sound/core/seq/oss/seq_oss_event.h b/sound/core/seq/oss/seq_oss_event.h
new file mode 100644
index 00000000000..bf1d4d3f53c
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_event.h
@@ -0,0 +1,112 @@
+/*
+ * OSS compatible sequencer driver
+ *
+ * seq_oss_event.h - OSS event queue record
+ *
+ * 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.