Linux-2.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!
diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c
new file mode 100644
index 0000000..972edc6
--- /dev/null
+++ b/sound/oss/midi_synth.c
@@ -0,0 +1,697 @@
+/*
+ * sound/midi_synth.c
+ *
+ * High level midi sequencer manager for dumb MIDI interfaces.
+ */
+/*
+ * 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)
+ * Andrew Veliath  : fixed running status in MIDI input state machine
+ */
+#define USE_SEQ_MACROS
+#define USE_SIMPLE_MACROS
+
+#include "sound_config.h"
+
+#define _MIDI_SYNTH_C_
+
+#include "midi_synth.h"
+
+static int      midi2synth[MAX_MIDI_DEV];
+static int      sysex_state[MAX_MIDI_DEV] =
+{0};
+static unsigned char prev_out_status[MAX_MIDI_DEV];
+
+#define STORE(cmd) \
+{ \
+  int len; \
+  unsigned char obuf[8]; \
+  cmd; \
+  seq_input_event(obuf, len); \
+}
+
+#define _seqbuf obuf
+#define _seqbufptr 0
+#define _SEQ_ADVBUF(x) len=x
+
+void
+do_midi_msg(int synthno, unsigned char *msg, int mlen)
+{
+	switch (msg[0] & 0xf0)
+	  {
+	  case 0x90:
+		  if (msg[2] != 0)
+		    {
+			    STORE(SEQ_START_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2]));
+			    break;
+		    }
+		  msg[2] = 64;
+
+	  case 0x80:
+		  STORE(SEQ_STOP_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2]));
+		  break;
+
+	  case 0xA0:
+		  STORE(SEQ_KEY_PRESSURE(synthno, msg[0] & 0x0f, msg[1], msg[2]));
+		  break;
+
+	  case 0xB0:
+		  STORE(SEQ_CONTROL(synthno, msg[0] & 0x0f,
+				    msg[1], msg[2]));
+		  break;
+
+	  case 0xC0:
+		  STORE(SEQ_SET_PATCH(synthno, msg[0] & 0x0f, msg[1]));
+		  break;
+
+	  case 0xD0:
+		  STORE(SEQ_CHN_PRESSURE(synthno, msg[0] & 0x0f, msg[1]));
+		  break;
+
+	  case 0xE0:
+		  STORE(SEQ_BENDER(synthno, msg[0] & 0x0f,
+			      (msg[1] & 0x7f) | ((msg[2] & 0x7f) << 7)));
+		  break;
+
+	  default:
+		  /* printk( "MPU: Unknown midi channel message %02x\n",  msg[0]); */
+		  ;
+	  }
+}
+
+static void
+midi_outc(int midi_dev, int data)
+{
+	int             timeout;
+
+	for (timeout = 0; timeout < 3200; timeout++)
+		if (midi_devs[midi_dev]->outputc(midi_dev, (unsigned char) (data & 0xff)))
+		  {
+			  if (data & 0x80)	/*
+						 * Status byte
+						 */
+				  prev_out_status[midi_dev] =
+				      (unsigned char) (data & 0xff);	/*
+									 * Store for running status
+									 */
+			  return;	/*
+					 * Mission complete
+					 */
+		  }
+	/*
+	 * Sorry! No space on buffers.
+	 */
+	printk("Midi send timed out\n");
+}
+
+static int
+prefix_cmd(int midi_dev, unsigned char status)
+{
+	if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL)
+		return 1;
+
+	return midi_devs[midi_dev]->prefix_cmd(midi_dev, status);
+}
+
+static void
+midi_synth_input(int orig_dev, unsigned char data)
+{
+	int             dev;
+	struct midi_input_info *inc;
+
+	static unsigned char len_tab[] =	/* # of data bytes following a status
+						 */
+	{
+		2,		/* 8x */
+		2,		/* 9x */
+		2,		/* Ax */
+		2,		/* Bx */
+		1,		/* Cx */
+		1,		/* Dx */
+		2,		/* Ex */
+		0		/* Fx */
+	};
+
+	if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL)
+		return;
+
+	if (data == 0xfe)	/* Ignore active sensing */
+		return;
+
+	dev = midi2synth[orig_dev];
+	inc = &midi_devs[orig_dev]->in_info;
+
+	switch (inc->m_state)
+	  {
+	  case MST_INIT:
+		  if (data & 0x80)	/* MIDI status byte */
+		    {
+			    if ((data & 0xf0) == 0xf0)	/* Common message */
+			      {
+				      switch (data)
+					{
+					case 0xf0:	/* Sysex */
+						inc->m_state = MST_SYSEX;
+						break;	/* Sysex */
+
+					case 0xf1:	/* MTC quarter frame */
+					case 0xf3:	/* Song select */
+						inc->m_state = MST_DATA;
+						inc->m_ptr = 1;
+						inc->m_left = 1;
+						inc->m_buf[0] = data;
+						break;
+
+					case 0xf2:	/* Song position pointer */
+						inc->m_state = MST_DATA;
+						inc->m_ptr = 1;
+						inc->m_left = 2;
+						inc->m_buf[0] = data;
+						break;
+
+					default:
+						inc->m_buf[0] = data;
+						inc->m_ptr = 1;
+						do_midi_msg(dev, inc->m_buf, inc->m_ptr);
+						inc->m_ptr = 0;
+						inc->m_left = 0;
+					}
+			    } else
+			      {
+				      inc->m_state = MST_DATA;
+				      inc->m_ptr = 1;
+				      inc->m_left = len_tab[(data >> 4) - 8];
+				      inc->m_buf[0] = inc->m_prev_status = data;
+			      }
+		    } else if (inc->m_prev_status & 0x80) {
+			    /* Data byte (use running status) */
+			    inc->m_ptr = 2;
+			    inc->m_buf[1] = data;
+			    inc->m_buf[0] = inc->m_prev_status;
+			    inc->m_left = len_tab[(inc->m_buf[0] >> 4) - 8] - 1;
+			    if (inc->m_left > 0)
+				    inc->m_state = MST_DATA; /* Not done yet */
+			    else {
+				    inc->m_state = MST_INIT;
+				    do_midi_msg(dev, inc->m_buf, inc->m_ptr);
+				    inc->m_ptr = 0;
+			    }
+		    }
+		  break;	/* MST_INIT */
+
+	  case MST_DATA:
+		  inc->m_buf[inc->m_ptr++] = data;
+		  if (--inc->m_left <= 0)
+		    {
+			    inc->m_state = MST_INIT;
+			    do_midi_msg(dev, inc->m_buf, inc->m_ptr);
+			    inc->m_ptr = 0;
+		    }
+		  break;	/* MST_DATA */
+
+	  case MST_SYSEX:
+		  if (data == 0xf7)	/* Sysex end */
+		    {
+			    inc->m_state = MST_INIT;
+			    inc->m_left = 0;
+			    inc->m_ptr = 0;
+		    }
+		  break;	/* MST_SYSEX */
+
+	  default:
+		  printk("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state, (int) data);
+		  inc->m_state = MST_INIT;
+	  }
+}
+
+static void
+leave_sysex(int dev)
+{
+	int             orig_dev = synth_devs[dev]->midi_dev;
+	int             timeout = 0;
+
+	if (!sysex_state[dev])
+		return;
+
+	sysex_state[dev] = 0;
+
+	while (!midi_devs[orig_dev]->outputc(orig_dev, 0xf7) &&
+	       timeout < 1000)
+		timeout++;
+
+	sysex_state[dev] = 0;
+}
+
+static void
+midi_synth_output(int dev)
+{
+	/*
+	 * Currently NOP
+	 */
+}
+
+int midi_synth_ioctl(int dev, unsigned int cmd, void __user *arg)
+{
+	/*
+	 * int orig_dev = synth_devs[dev]->midi_dev;
+	 */
+
+	switch (cmd) {
+
+	case SNDCTL_SYNTH_INFO:
+		if (__copy_to_user(arg, synth_devs[dev]->info, sizeof(struct synth_info)))
+			return -EFAULT;
+		return 0;
+		
+	case SNDCTL_SYNTH_MEMAVL:
+		return 0x7fffffff;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+int
+midi_synth_kill_note(int dev, int channel, int note, int velocity)
+{
+	int             orig_dev = synth_devs[dev]->midi_dev;
+	int             msg, chn;
+
+	if (note < 0 || note > 127)
+		return 0;
+	if (channel < 0 || channel > 15)
+		return 0;
+	if (velocity < 0)
+		velocity = 0;
+	if (velocity > 127)
+		velocity = 127;
+
+	leave_sysex(dev);
+
+	msg = prev_out_status[orig_dev] & 0xf0;
+	chn = prev_out_status[orig_dev] & 0x0f;
+
+	if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80))
+	  {			/*
+				 * Use running status
+				 */
+		  if (!prefix_cmd(orig_dev, note))
+			  return 0;
+
+		  midi_outc(orig_dev, note);
+
+		  if (msg == 0x90)	/*
+					 * Running status = Note on
+					 */
+			  midi_outc(orig_dev, 0);	/*
+							   * Note on with velocity 0 == note
+							   * off
+							 */
+		  else
+			  midi_outc(orig_dev, velocity);
+	} else
+	  {
+		  if (velocity == 64)
+		    {
+			    if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f)))
+				    return 0;
+			    midi_outc(orig_dev, 0x90 | (channel & 0x0f));	/*
+										 * Note on
+										 */
+			    midi_outc(orig_dev, note);
+			    midi_outc(orig_dev, 0);	/*
+							 * Zero G
+							 */
+		  } else
+		    {
+			    if (!prefix_cmd(orig_dev, 0x80 | (channel & 0x0f)))
+				    return 0;
+			    midi_outc(orig_dev, 0x80 | (channel & 0x0f));	/*
+										 * Note off
+										 */
+			    midi_outc(orig_dev, note);
+			    midi_outc(orig_dev, velocity);
+		    }
+	  }
+
+	return 0;
+}
+
+int
+midi_synth_set_instr(int dev, int channel, int instr_no)
+{
+	int             orig_dev = synth_devs[dev]->midi_dev;
+
+	if (instr_no < 0 || instr_no > 127)
+		instr_no = 0;
+	if (channel < 0 || channel > 15)
+		return 0;
+
+	leave_sysex(dev);
+
+	if (!prefix_cmd(orig_dev, 0xc0 | (channel & 0x0f)))
+		return 0;
+	midi_outc(orig_dev, 0xc0 | (channel & 0x0f));	/*
+							 * Program change
+							 */
+	midi_outc(orig_dev, instr_no);
+
+	return 0;
+}
+
+int
+midi_synth_start_note(int dev, int channel, int note, int velocity)
+{
+	int             orig_dev = synth_devs[dev]->midi_dev;
+	int             msg, chn;
+
+	if (note < 0 || note > 127)
+		return 0;
+	if (channel < 0 || channel > 15)
+		return 0;
+	if (velocity < 0)
+		velocity = 0;
+	if (velocity > 127)
+		velocity = 127;
+
+	leave_sysex(dev);
+
+	msg = prev_out_status[orig_dev] & 0xf0;
+	chn = prev_out_status[orig_dev] & 0x0f;
+
+	if (chn == channel && msg == 0x90)
+	  {			/*
+				 * Use running status
+				 */
+		  if (!prefix_cmd(orig_dev, note))
+			  return 0;
+		  midi_outc(orig_dev, note);
+		  midi_outc(orig_dev, velocity);
+	} else
+	  {
+		  if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f)))
+			  return 0;
+		  midi_outc(orig_dev, 0x90 | (channel & 0x0f));		/*
+									 * Note on
+									 */
+		  midi_outc(orig_dev, note);
+		  midi_outc(orig_dev, velocity);
+	  }
+	return 0;
+}
+
+void
+midi_synth_reset(int dev)
+{
+
+	leave_sysex(dev);
+}
+
+int
+midi_synth_open(int dev, int mode)
+{
+	int             orig_dev = synth_devs[dev]->midi_dev;
+	int             err;
+	struct midi_input_info *inc;
+
+	if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL)
+		return -ENXIO;
+
+	midi2synth[orig_dev] = dev;
+	sysex_state[dev] = 0;
+	prev_out_status[orig_dev] = 0;
+
+	if ((err = midi_devs[orig_dev]->open(orig_dev, mode,
+			       midi_synth_input, midi_synth_output)) < 0)
+		return err;
+	inc = &midi_devs[orig_dev]->in_info;
+
+	/* save_flags(flags);
+	cli(); 
+	don't know against what irqhandler to protect*/
+	inc->m_busy = 0;
+	inc->m_state = MST_INIT;
+	inc->m_ptr = 0;
+	inc->m_left = 0;
+	inc->m_prev_status = 0x00;
+	/* restore_flags(flags); */
+
+	return 1;
+}
+
+void
+midi_synth_close(int dev)
+{
+	int             orig_dev = synth_devs[dev]->midi_dev;
+
+	leave_sysex(dev);
+
+	/*
+	 * Shut up the synths by sending just single active sensing message.
+	 */
+	midi_devs[orig_dev]->outputc(orig_dev, 0xfe);
+
+	midi_devs[orig_dev]->close(orig_dev);
+}
+
+void
+midi_synth_hw_control(int dev, unsigned char *event)
+{
+}
+
+int
+midi_synth_load_patch(int dev, int format, const char __user *addr,
+		      int offs, int count, int pmgr_flag)
+{
+	int             orig_dev = synth_devs[dev]->midi_dev;
+
+	struct sysex_info sysex;
+	int             i;
+	unsigned long   left, src_offs, eox_seen = 0;
+	int             first_byte = 1;
+	int             hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex;
+
+	leave_sysex(dev);
+
+	if (!prefix_cmd(orig_dev, 0xf0))
+		return 0;
+
+	if (format != SYSEX_PATCH)
+	{
+/*		  printk("MIDI Error: Invalid patch format (key) 0x%x\n", format);*/
+		  return -EINVAL;
+	}
+	if (count < hdr_size)
+	{
+/*		printk("MIDI Error: Patch header too short\n");*/
+		return -EINVAL;
+	}
+	count -= hdr_size;
+
+	/*
+	 * Copy the header from user space but ignore the first bytes which have
+	 * been transferred already.
+	 */
+
+	if(copy_from_user(&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs))
+		return -EFAULT;
+ 
+ 	if (count < sysex.len)
+	{
+/*		printk(KERN_WARNING "MIDI Warning: Sysex record too short (%d<%d)\n", count, (int) sysex.len);*/
+		sysex.len = count;
+	}
+  	left = sysex.len;
+  	src_offs = 0;
+
+	for (i = 0; i < left && !signal_pending(current); i++)
+	{
+		unsigned char   data;
+
+		get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i]));
+
+		eox_seen = (i > 0 && data & 0x80);	/* End of sysex */
+
+		if (eox_seen && data != 0xf7)
+			data = 0xf7;
+
+		if (i == 0)
+		{
+			if (data != 0xf0)
+			{
+				printk(KERN_WARNING "midi_synth: Sysex start missing\n");
+				return -EINVAL;
+			}
+		}
+		while (!midi_devs[orig_dev]->outputc(orig_dev, (unsigned char) (data & 0xff)) &&
+			!signal_pending(current))
+			schedule();
+
+		if (!first_byte && data & 0x80)
+			return 0;
+		first_byte = 0;
+	}
+
+	if (!eox_seen)
+		midi_outc(orig_dev, 0xf7);
+	return 0;
+}
+  
+void midi_synth_panning(int dev, int channel, int pressure)
+{
+}
+  
+void midi_synth_aftertouch(int dev, int channel, int pressure)
+{
+	int             orig_dev = synth_devs[dev]->midi_dev;
+	int             msg, chn;
+
+	if (pressure < 0 || pressure > 127)
+		return;
+	if (channel < 0 || channel > 15)
+		return;
+
+	leave_sysex(dev);
+
+	msg = prev_out_status[orig_dev] & 0xf0;
+	chn = prev_out_status[orig_dev] & 0x0f;
+
+	if (msg != 0xd0 || chn != channel)	/*
+						 * Test for running status
+						 */
+	  {
+		  if (!prefix_cmd(orig_dev, 0xd0 | (channel & 0x0f)))
+			  return;
+		  midi_outc(orig_dev, 0xd0 | (channel & 0x0f));		/*
+									 * Channel pressure
+									 */
+	} else if (!prefix_cmd(orig_dev, pressure))
+		return;
+
+	midi_outc(orig_dev, pressure);
+}
+
+void
+midi_synth_controller(int dev, int channel, int ctrl_num, int value)
+{
+	int             orig_dev = synth_devs[dev]->midi_dev;
+	int             chn, msg;
+
+	if (ctrl_num < 0 || ctrl_num > 127)
+		return;
+	if (channel < 0 || channel > 15)
+		return;
+
+	leave_sysex(dev);
+
+	msg = prev_out_status[orig_dev] & 0xf0;
+	chn = prev_out_status[orig_dev] & 0x0f;
+
+	if (msg != 0xb0 || chn != channel)
+	  {
+		  if (!prefix_cmd(orig_dev, 0xb0 | (channel & 0x0f)))
+			  return;
+		  midi_outc(orig_dev, 0xb0 | (channel & 0x0f));
+	} else if (!prefix_cmd(orig_dev, ctrl_num))
+		return;
+
+	midi_outc(orig_dev, ctrl_num);
+	midi_outc(orig_dev, value & 0x7f);
+}
+
+void
+midi_synth_bender(int dev, int channel, int value)
+{
+	int             orig_dev = synth_devs[dev]->midi_dev;
+	int             msg, prev_chn;
+
+	if (channel < 0 || channel > 15)
+		return;
+
+	if (value < 0 || value > 16383)
+		return;
+
+	leave_sysex(dev);
+
+	msg = prev_out_status[orig_dev] & 0xf0;
+	prev_chn = prev_out_status[orig_dev] & 0x0f;
+
+	if (msg != 0xd0 || prev_chn != channel)		/*
+							 * Test for running status
+							 */
+	  {
+		  if (!prefix_cmd(orig_dev, 0xe0 | (channel & 0x0f)))
+			  return;
+		  midi_outc(orig_dev, 0xe0 | (channel & 0x0f));
+	} else if (!prefix_cmd(orig_dev, value & 0x7f))
+		return;
+
+	midi_outc(orig_dev, value & 0x7f);
+	midi_outc(orig_dev, (value >> 7) & 0x7f);
+}
+
+void
+midi_synth_setup_voice(int dev, int voice, int channel)
+{
+}
+
+int
+midi_synth_send_sysex(int dev, unsigned char *bytes, int len)
+{
+	int             orig_dev = synth_devs[dev]->midi_dev;
+	int             i;
+
+	for (i = 0; i < len; i++)
+	  {
+		  switch (bytes[i])
+		    {
+		    case 0xf0:	/* Start sysex */
+			    if (!prefix_cmd(orig_dev, 0xf0))
+				    return 0;
+			    sysex_state[dev] = 1;
+			    break;
+
+		    case 0xf7:	/* End sysex */
+			    if (!sysex_state[dev])	/* Orphan sysex end */
+				    return 0;
+			    sysex_state[dev] = 0;
+			    break;
+
+		    default:
+			    if (!sysex_state[dev])
+				    return 0;
+
+			    if (bytes[i] & 0x80)	/* Error. Another message before sysex end */
+			      {
+				      bytes[i] = 0xf7;	/* Sysex end */
+				      sysex_state[dev] = 0;
+			      }
+		    }
+
+		  if (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i]))
+		    {
+/*
+ * Hardware level buffer is full. Abort the sysex message.
+ */
+
+			    int             timeout = 0;
+
+			    bytes[i] = 0xf7;
+			    sysex_state[dev] = 0;
+
+			    while (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i]) &&
+				   timeout < 1000)
+				    timeout++;
+		    }
+		  if (!sysex_state[dev])
+			  return 0;
+	  }
+
+	return 0;
+}