diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-05-03 21:08:42 +0400 |
commit | 1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch) | |
tree | 4495d23e7b54ab5700e3839081e797c1eafe0db9 /kernel/drv/oss_midiloop | |
download | oss4-upstream.tar.gz |
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'kernel/drv/oss_midiloop')
-rw-r--r-- | kernel/drv/oss_midiloop/.config | 1 | ||||
-rw-r--r-- | kernel/drv/oss_midiloop/.devices | 1 | ||||
-rw-r--r-- | kernel/drv/oss_midiloop/.name | 1 | ||||
-rw-r--r-- | kernel/drv/oss_midiloop/.params | 5 | ||||
-rw-r--r-- | kernel/drv/oss_midiloop/oss_midiloop.c | 412 | ||||
-rw-r--r-- | kernel/drv/oss_midiloop/oss_midiloop.man | 44 |
6 files changed, 464 insertions, 0 deletions
diff --git a/kernel/drv/oss_midiloop/.config b/kernel/drv/oss_midiloop/.config new file mode 100644 index 0000000..c10d582 --- /dev/null +++ b/kernel/drv/oss_midiloop/.config @@ -0,0 +1 @@ +bus=VIRTUAL diff --git a/kernel/drv/oss_midiloop/.devices b/kernel/drv/oss_midiloop/.devices new file mode 100644 index 0000000..9389c68 --- /dev/null +++ b/kernel/drv/oss_midiloop/.devices @@ -0,0 +1 @@ +oss_midiloop oss_midiloop OSS MIDI Loopback driver diff --git a/kernel/drv/oss_midiloop/.name b/kernel/drv/oss_midiloop/.name new file mode 100644 index 0000000..1b2e06b --- /dev/null +++ b/kernel/drv/oss_midiloop/.name @@ -0,0 +1 @@ +MIDI loopback pseudo device diff --git a/kernel/drv/oss_midiloop/.params b/kernel/drv/oss_midiloop/.params new file mode 100644 index 0000000..9e33e88 --- /dev/null +++ b/kernel/drv/oss_midiloop/.params @@ -0,0 +1,5 @@ +int midiloop_instances = 1; /* Number of loopback MIDI devs to install */ +/* + * midiloop_instances gives the number of MIDI loopback devices to be created. + * The default value is 1 + */ diff --git a/kernel/drv/oss_midiloop/oss_midiloop.c b/kernel/drv/oss_midiloop/oss_midiloop.c new file mode 100644 index 0000000..5c9082a --- /dev/null +++ b/kernel/drv/oss_midiloop/oss_midiloop.c @@ -0,0 +1,412 @@ +/* + * Purpose: MIDI loopback driver + */ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ + +#include "oss_midiloop_cfg.h" +#include "midi_core.h" + +#define MIDI_SYNTH_NAME "OSS loopback MIDI" +#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT + +#define MAX_INSTANCES 8 +#define CLIENT_NAME "MIDI loopback" +#define SERVER_NAME "MIDI loopback server side" + +#define POLL_HZ (OSS_HZ/100) + +static int open_clients = 0; +static int open_servers = 0; + +typedef struct midiloop_devc +{ + oss_device_t *osdev; + oss_mutex_t mutex; + + int instance_no; + int side; +#define SIDE_SERVER 0 +#define SIDE_CLIENT 0 + int midi_dev; + struct midiloop_devc *client, *server, *peer; + + int open_mode; + oss_midi_inputbyte_t inputbyte_func; + oss_midi_inputbuf_t inputbuf_func; + oss_longname_t song_name; + +} midiloop_devc; + +static midiloop_devc midiloop_devs[2 * MAX_INSTANCES] = { {0} }; +static int ndevs = 0; + +static int +midiloop_open_server (int dev, int mode, oss_midi_inputbyte_t inputbyte, + oss_midi_inputbuf_t inputbuf, + oss_midi_outputintr_t outputintr) +{ + oss_native_word flags; + midiloop_devc *devc, *client_devc; + char *cmd; + int client_dev; + + devc = midi_devs[dev]->devc; + + client_devc = devc->client; + + client_dev = client_devc->midi_dev; + + MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); + if (devc->open_mode) + { + MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); + return OSS_EBUSY; + } + + devc->open_mode = mode; + devc->inputbyte_func = inputbyte; + devc->inputbuf_func = inputbuf; + + open_servers++; + + if ((cmd = midi_devs[dev]->cmd) != NULL) + { + sprintf (midi_devs[client_dev]->name, CLIENT_NAME " (%s)", cmd); + } + MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); + + return 0; +} + +static void +midiloop_close_server (int dev, int mode) +{ + oss_native_word flags; + midiloop_devc *devc, *client_devc; + int client_dev; + + devc = midi_devs[dev]->devc; + client_devc = devc->client; + client_dev = client_devc->midi_dev; + + MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); + devc->open_mode = 0; + devc->inputbyte_func = NULL; + devc->inputbuf_func = NULL; + strcpy (midi_devs[client_dev]->name, CLIENT_NAME); + midi_devs[client_dev]->latency = -1; /* Not indicated */ + + open_servers--; + MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); +} + +static int +midiloop_open_client (int dev, int mode, oss_midi_inputbyte_t inputbyte, + oss_midi_inputbuf_t inputbuf, + oss_midi_outputintr_t outputintr) +{ + oss_native_word flags; + midiloop_devc *devc; + + devc = midi_devs[dev]->devc; + + MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); + if (devc->open_mode) + { + MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); + return OSS_EBUSY; + } + + devc->open_mode = mode; + devc->inputbyte_func = inputbyte; + devc->inputbuf_func = inputbuf; + open_clients++; + + /* Notify the server */ + if (devc->server->open_mode & OPEN_READ) + { + if (devc->server->inputbyte_func != NULL) + devc->server->inputbyte_func (devc->server->midi_dev, 0xfa); /* Start */ + + /* Restart the MTC timer of the server side (if necessary) */ + if (midi_devs[devc->server->midi_dev]->mtc_timebase > -1) + { + int timebase = 25; + oss_midi_ioctl (devc->server->midi_dev, NULL, SNDCTL_MIDI_MTCINPUT, + (ioctl_arg) & timebase); + } + } + + MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); + + return 0; +} + +static void +midiloop_close_client (int dev, int mode) +{ + oss_native_word flags; + midiloop_devc *devc; + + devc = midi_devs[dev]->devc; + + MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); + devc->open_mode = 0; + devc->inputbyte_func = NULL; + devc->inputbuf_func = NULL; + open_clients--; + + /* Notify the server */ + if (devc->server->open_mode & OPEN_READ) + if (devc->server->inputbyte_func != NULL) + devc->server->inputbyte_func (devc->server->midi_dev, 0xfc); /* Stop */ + MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); + /* Halt the MTC timer of the server side (if necessary) */ + if (midi_devs[devc->server->midi_dev]->mtc_timebase > 0) + { + int timebase = 0; + oss_midi_ioctl (devc->server->midi_dev, NULL, SNDCTL_MIDI_MTCINPUT, + (ioctl_arg) & timebase); + } +} + +static int +midiloop_out (int dev, unsigned char midi_byte) +{ + midiloop_devc *devc; + oss_native_word flags; + int ok = 0; + + devc = midi_devs[dev]->devc; + + if (devc->peer->open_mode == 0) + return 1; + MUTEX_ENTER_IRQDISABLE (devc->peer->mutex, flags); + if (devc->peer->inputbyte_func != NULL) + { + ok = devc->peer->inputbyte_func (devc->peer->midi_dev, midi_byte); + } + MUTEX_EXIT_IRQRESTORE (devc->peer->mutex, flags); + return ok; +} + +static int +midiloop_bulk_out (int dev, unsigned char *buf, int len) +{ + midiloop_devc *devc; + oss_native_word flags; + int ok = 0; + + devc = midi_devs[dev]->devc; + + MUTEX_ENTER_IRQDISABLE (devc->peer->mutex, flags); + if (devc->peer->open_mode == 0 || devc->peer->inputbuf_func == NULL) + { + MUTEX_EXIT_IRQRESTORE (devc->peer->mutex, flags); + return len; + } + + ok = devc->peer->inputbuf_func (devc->peer->midi_dev, buf, len); + MUTEX_EXIT_IRQRESTORE (devc->peer->mutex, flags); + return ok; +} + +static void +midiloop_timer_setup (int dev /* Client dev */ ) +{ + midiloop_devc *devc, *server_devc; + int client_dev; + int server_dev; + + devc = midi_devs[dev]->devc; + server_devc = devc->server; + client_dev = devc->midi_dev; + server_dev = devc->server->midi_dev; + + oss_midi_copy_timer (server_dev, client_dev); +} + +static int +midiloop_ioctl (int dev, unsigned cmd, ioctl_arg arg) +{ + char *song_name; + oss_native_word flags; + midiloop_devc *devc, *client_devc; + int client_dev; + + devc = midi_devs[dev]->devc; + client_devc = devc->client; + client_dev = client_devc->midi_dev; + + switch (cmd) + { + case SNDCTL_SETSONG: + if (devc->side != SIDE_CLIENT) + return 0; + + song_name = (char *) arg; + song_name[OSS_LONGNAME_SIZE - 1] = 0; + + MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); + strcpy (devc->song_name, song_name); + MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); + return 0; + break; + + case SNDCTL_SETNAME: + if (devc->side != SIDE_SERVER) + return 0; + + song_name = (char *) arg; + song_name[OSS_LONGNAME_SIZE - 1] = 0; + + MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); + strcpy (midi_devs[devc->client->midi_dev]->name, song_name); + MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); + return 0; + break; + + case SNDCTL_GETSONG: + song_name = (char *) arg; + memset (song_name, 0, OSS_LONGNAME_SIZE); + + MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); + if (devc->side == SIDE_SERVER) + strcpy (song_name, devc->peer->song_name); + else + strcpy (song_name, devc->song_name); + MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); + return 0; + break; + + case SNDCTL_MIDI_SET_LATENCY: + if (devc->side != SIDE_SERVER) + return OSS_EINVAL; + if (*arg < -1 || *arg > 10000000) + return OSS_EINVAL; + midi_devs[devc->client->midi_dev]->latency = *arg; + break; + } + return OSS_EINVAL; +} + +static midi_driver_t midiloop_client_driver = { + midiloop_open_client, + midiloop_close_client, + midiloop_ioctl, + midiloop_out, + midiloop_bulk_out, + MIDI_PAYLOAD_SIZE, + NULL, + NULL, + midiloop_timer_setup +}; + +static midi_driver_t midiloop_server_driver = { + midiloop_open_server, + midiloop_close_server, + midiloop_ioctl, + midiloop_out, + midiloop_bulk_out, + MIDI_PAYLOAD_SIZE +}; + +static void +attach_midiloop_dev (oss_device_t * osdev) +{ + midiloop_devc *server_devc = NULL, *client_devc = NULL; + + if (POLL_HZ < 1) + { + cmn_err (CE_CONT, "midiloop: Too low system timer resolution\n"); + return; + } + + if (ndevs >= MAX_INSTANCES) + { + cmn_err (CE_CONT, "MidiLoop: Too many instances\n"); + return; + } + + client_devc = &midiloop_devs[ndevs * 2]; + client_devc->osdev = osdev; + MUTEX_INIT (client_devc->osdev, client_devc->mutex, MH_DRV); + client_devc->instance_no = ndevs; + + client_devc->midi_dev = + oss_install_mididev (OSS_MIDI_DRIVER_VERSION, "LOOP", CLIENT_NAME, + &midiloop_client_driver, sizeof (midi_driver_t), + MFLAG_VIRTUAL | MFLAG_CLIENT, client_devc, + client_devc->osdev); + + server_devc = &midiloop_devs[ndevs * 2 + 1]; + server_devc->osdev = osdev; + MUTEX_INIT (server_devc->osdev, server_devc->mutex, MH_DRV); + server_devc->instance_no = ndevs; + + midi_devs[client_devc->midi_dev]->latency = 1000000; + + server_devc->midi_dev = + oss_install_mididev (OSS_MIDI_DRIVER_VERSION, "LOOP_S", SERVER_NAME, + &midiloop_server_driver, sizeof (midi_driver_t), + MFLAG_NOSEQUENCER | MFLAG_VIRTUAL | MFLAG_SERVER | + MFLAG_SELFTIMING, server_devc, server_devc->osdev); + + client_devc->server = client_devc->peer = server_devc; + client_devc->client = client_devc; + client_devc->side = SIDE_CLIENT; + + server_devc->client = server_devc->peer = client_devc; + server_devc->server = server_devc; + server_devc->side = SIDE_SERVER; + + ndevs++; +} + +int +oss_midiloop_attach (oss_device_t * osdev) +{ + extern int midiloop_instances; + int i; + + oss_register_device (osdev, "OSS MIDI loopback driver"); + + if (midiloop_instances > MAX_INSTANCES) + midiloop_instances = MAX_INSTANCES; + for (i = 0; i < midiloop_instances; i++) + { + attach_midiloop_dev (osdev); + } + + return 1; +} + +int +oss_midiloop_detach (oss_device_t * osdev) +{ + int i, err; + + if ((err = oss_disable_device (osdev)) < 0) + return 0; + + for (i = 0; i < 2 * ndevs; i++) + { + midiloop_devc *devc; + + devc = &midiloop_devs[i]; + } + + oss_unregister_device (osdev); + + return 1; +} diff --git a/kernel/drv/oss_midiloop/oss_midiloop.man b/kernel/drv/oss_midiloop/oss_midiloop.man new file mode 100644 index 0000000..a3ee97d --- /dev/null +++ b/kernel/drv/oss_midiloop/oss_midiloop.man @@ -0,0 +1,44 @@ +NAME +oss_midiloop - Loopback MIDI driver. + +DESCRIPTION +The loopback midi driver makes it possible to create special purpose +virtual midi devices based on user land server processes. + +INTRODUCTION +MIDI loopback devices are like named pipes or pseudo terminals. They are +grouped in client and server device pairs. The server side device must be open +before the client side device can be opened. + + SERVER SIDE DEVICE +The server side device is used by some special application (such as a +software based MIDI synthesizer) to receice MIDI events from the applications +that want to play MIDI. + + CLIENT SIDE DEVICE +Client applications such as MIDI players open the client side device when they +need to play some MIDI stream (file). The client side device behaves like any +"ordinary" MIDI device. However it cannot be opened when there is no program +connected to the server side. + +COMPATIBILITY ISSUES +MIDI loopback devices differ from "normal" MIDI devices because an +application is needed at the both ends of the loop. The loop device +will return a "Connection reset by peer" error (ECONNRESET) error. Applications +designed to be used as loopback based server applications can/should use this +error (returned by read or write) as an end-of-stream indication. + +OPTIONS +o midiloop_instances: Specifies how many loopback client/server MIDI device + pairs to be created. + Values: 1-16 Default: 1 + +KNOWN PROBLEMS +None + +FILES +CONFIGFILEPATH/oss_midiloop.conf Device configuration file + +AUTHOR +4Front Technologies + |