/*
* sound/oss/sequencer.c
*
* The sequencer personality manager.
*/
/*
* Copyright (C) by Hannu Savolainen 1993-1997
*
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
/*
* Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
* Alan Cox : reformatted and fixed a pair of null pointer bugs
*/
#include <linux/kmod.h>
#include <linux/spinlock.h>
#include "sound_config.h"
#include "midi_ctrl.h"
#include "sleep.h"
static int sequencer_ok;
static struct sound_timer_operations *tmr;
static int tmr_no = -1; /* Currently selected timer */
static int pending_timer = -1; /* For timer change operation */
extern unsigned long seq_time;
static int obsolete_api_used;
static DEFINE_SPINLOCK(lock);
/*
* Local counts for number of synth and MIDI devices. These are initialized
* by the sequencer_open.
*/
static int max_mididev;
static int max_synthdev;
/*
* The seq_mode gives the operating mode of the sequencer:
* 1 = level1 (the default)
* 2 = level2 (extended capabilities)
*/
#define SEQ_1 1
#define SEQ_2 2
static int seq_mode = SEQ_1;
static DECLARE_WAIT_QUEUE_HEAD(seq_sleeper);
static DECLARE_WAIT_QUEUE_HEAD(midi_sleeper);
static int midi_opened[MAX_MIDI_DEV];
static int midi_written[MAX_MIDI_DEV];
static unsigned long prev_input_time;
static int prev_event_time;
#include "tuning.h"
#define EV_SZ 8
#define IEV_SZ 8
static unsigned char *queue;
static unsigned char *iqueue;
static volatile int qhead, qtail, qlen;
static volatile int iqhead, iqtail, iqlen;
static volatile int seq_playing;
static volatile int sequencer_busy;
static int output_threshold;
static long pre_event_timeout;
static unsigned synth_open_mask;
static int seq_queue(unsigned char *note, char nonblock);
static void seq_startplay(void);
static int seq_sync(void);
static void seq_reset(void);
#if MAX_SYNTH_DEV > 15
#error Too many synthesizer devices enabled.
#endif
int sequencer_read(int dev, struct file *file, char __user *buf, int count)
{
int c = count, p = 0;
int ev_len;
unsigned long flags;
dev = dev >> 4;
ev_len = seq_mode == SEQ_1 ? 4 : 8;
spin_lock_irqsave(&lock,flags);
if (!iqlen)
{
spin_unlock_irqrestore(&lock,flags);
if (file->f_flags & O_NONBLOCK) {
return -EAGAIN;
}
oss_broken_sleep_on(&midi_sleeper, pre_event_timeout);
spin_lock_irqsave(&lock,flags);
if (!iqlen)
{
spin_unlock_irqrestore(&lock,flags);
return 0;
}
}
while (iqlen && c >= ev_len)
{
char *fixit = (char *) &iqueue[iqhead * IEV_SZ];
spin_unlock_irqrestore(&l
|