OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [sound/] [midibuf.c] - Rev 1777

Go to most recent revision | Compare with Previous | Blame | View Log

/*
 * sound/midibuf.c
 *
 * Device file manager for /dev/midi#
 */
/*
 * Copyright (C) by Hannu Savolainen 1993-1996
 *
 * USS/Lite 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.
 */
#include <linux/config.h>
 
 
#include "sound_config.h"
 
#if defined(CONFIG_MIDI)
 
/*
 * Don't make MAX_QUEUE_SIZE larger than 4000
 */
 
#define MAX_QUEUE_SIZE	4000
 
static wait_handle *midi_sleeper[MAX_MIDI_DEV] =
{NULL};
static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] =
{
  {0}};
static wait_handle *input_sleeper[MAX_MIDI_DEV] =
{NULL};
static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] =
{
  {0}};
 
struct midi_buf
  {
    int             len, head, tail;
    unsigned char   queue[MAX_QUEUE_SIZE];
  };
 
struct midi_parms
  {
    int             prech_timeout;	/*
					 * Timeout before the first ch
					 */
  };
 
static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] =
{NULL};
static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] =
{NULL};
static struct midi_parms parms[MAX_MIDI_DEV];
 
static void     midi_poll (unsigned long dummy);
 
 
static struct timer_list poll_timer =
{NULL, NULL, 0, 0, midi_poll};
static volatile int open_devs = 0;
 
#define DATA_AVAIL(q) (q->len)
#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)
 
#define QUEUE_BYTE(q, data) \
	if (SPACE_AVAIL(q)) \
	{ \
	  unsigned long flags; \
	  save_flags(flags);cli(); \
	  q->queue[q->tail] = (data); \
	  q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
	  restore_flags(flags); \
	}
 
#define REMOVE_BYTE(q, data) \
	if (DATA_AVAIL(q)) \
	{ \
	  unsigned long flags; \
	  save_flags(flags);cli(); \
	  data = q->queue[q->head]; \
	  q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
	  restore_flags(flags); \
	}
 
void
drain_midi_queue (int dev)
{
 
  /*
   * Give the Midi driver time to drain its output queues
   */
 
  if (midi_devs[dev]->buffer_status != NULL)
    while (!current_got_fatal_signal () &&
	   midi_devs[dev]->buffer_status (dev))
 
      {
	unsigned long   tlimit;
 
	if (HZ / 10)
	  current_set_timeout (tlimit = jiffies + (HZ / 10));
	else
	  tlimit = (unsigned long) -1;
	midi_sleep_flag[dev].flags = WK_SLEEP;
	module_interruptible_sleep_on (&midi_sleeper[dev]);
	if (!(midi_sleep_flag[dev].flags & WK_WAKEUP))
	  {
	    if (jiffies >= tlimit)
	      midi_sleep_flag[dev].flags |= WK_TIMEOUT;
	  }
	midi_sleep_flag[dev].flags &= ~WK_SLEEP;
      };
}
 
static void
midi_input_intr (int dev, unsigned char data)
{
  if (midi_in_buf[dev] == NULL)
    return;
 
  if (data == 0xfe)		/*
				 * Active sensing
				 */
    return;			/*
				 * Ignore
				 */
 
  if (SPACE_AVAIL (midi_in_buf[dev]))
    {
      QUEUE_BYTE (midi_in_buf[dev], data);
      if ((input_sleep_flag[dev].flags & WK_SLEEP))
	{
	  input_sleep_flag[dev].flags = WK_WAKEUP;
	  module_wake_up (&input_sleeper[dev]);
	};
    }
 
}
 
static void
midi_output_intr (int dev)
{
  /*
   * Currently NOP
   */
}
 
static void
midi_poll (unsigned long dummy)
{
  unsigned long   flags;
  int             dev;
 
  save_flags (flags);
  cli ();
  if (open_devs)
    {
      for (dev = 0; dev < num_midis; dev++)
	if (midi_out_buf[dev] != NULL)
	  {
	    while (DATA_AVAIL (midi_out_buf[dev]) &&
		   midi_devs[dev]->putc (dev,
			 midi_out_buf[dev]->queue[midi_out_buf[dev]->head]))
	      {
		midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
		midi_out_buf[dev]->len--;
	      }
 
	    if (DATA_AVAIL (midi_out_buf[dev]) < 100 &&
		(midi_sleep_flag[dev].flags & WK_SLEEP))
	      {
		midi_sleep_flag[dev].flags = WK_WAKEUP;
		module_wake_up (&midi_sleeper[dev]);
	      };
	  }
 
      {
	poll_timer.expires = (1) + jiffies;
	add_timer (&poll_timer);
      };			/*
				   * Come back later
				 */
    }
  restore_flags (flags);
}
 
int
MIDIbuf_open (int dev, struct fileinfo *file)
{
  int             mode, err;
 
  dev = dev >> 4;
  mode = file->mode & O_ACCMODE;
 
  if (num_midis > MAX_MIDI_DEV)
    {
      printk ("Sound: FATAL ERROR: Too many midi interfaces\n");
      num_midis = MAX_MIDI_DEV;
    }
 
  if (dev < 0 || dev >= num_midis)
    {
      printk ("Sound: Nonexistent MIDI interface %d\n", dev);
      return -(ENXIO);
    }
 
  /*
     *    Interrupts disabled. Be careful
   */
 
  if ((err = midi_devs[dev]->open (dev, mode,
				   midi_input_intr, midi_output_intr)) < 0)
    {
      return err;
    }
 
  parms[dev].prech_timeout = 0;
 
  midi_in_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf));
 
  if (midi_in_buf[dev] == NULL)
    {
      printk ("midi: Can't allocate buffer\n");
      midi_devs[dev]->close (dev);
      return -(EIO);
    }
  midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
 
  midi_out_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf));
 
  if (midi_out_buf[dev] == NULL)
    {
      printk ("midi: Can't allocate buffer\n");
      midi_devs[dev]->close (dev);
      vfree (midi_in_buf[dev]);
      midi_in_buf[dev] = NULL;
      return -(EIO);
    }
  midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
  open_devs++;
 
  midi_sleep_flag[dev].flags = WK_NONE;
  input_sleep_flag[dev].flags = WK_NONE;
 
  if (open_devs < 2)		/* This was first open */
    {
      ;
 
      {
	poll_timer.expires = (1) + jiffies;
	add_timer (&poll_timer);
      };			/* Start polling */
    }
 
  return err;
}
 
void
MIDIbuf_release (int dev, struct fileinfo *file)
{
  int             mode;
  unsigned long   flags;
 
  dev = dev >> 4;
  mode = file->mode & O_ACCMODE;
 
  if (dev < 0 || dev >= num_midis)
    return;
 
  save_flags (flags);
  cli ();
 
  /*
     * Wait until the queue is empty
   */
 
  if (mode != OPEN_READ)
    {
      midi_devs[dev]->putc (dev, 0xfe);		/*
						   * Active sensing to shut the
						   * devices
						 */
 
      while (!current_got_fatal_signal () &&
	     DATA_AVAIL (midi_out_buf[dev]))
 
	{
	  unsigned long   tlimit;
 
	  if (0)
	    current_set_timeout (tlimit = jiffies + (0));
	  else
	    tlimit = (unsigned long) -1;
	  midi_sleep_flag[dev].flags = WK_SLEEP;
	  module_interruptible_sleep_on (&midi_sleeper[dev]);
	  if (!(midi_sleep_flag[dev].flags & WK_WAKEUP))
	    {
	      if (jiffies >= tlimit)
		midi_sleep_flag[dev].flags |= WK_TIMEOUT;
	    }
	  midi_sleep_flag[dev].flags &= ~WK_SLEEP;
	};			/*
				   * Sync
				 */
 
      drain_midi_queue (dev);	/*
				 * Ensure the output queues are empty
				 */
    }
 
  restore_flags (flags);
 
  midi_devs[dev]->close (dev);
 
  vfree (midi_in_buf[dev]);
  vfree (midi_out_buf[dev]);
  midi_in_buf[dev] = NULL;
  midi_out_buf[dev] = NULL;
  if (open_devs < 2)
    del_timer (&poll_timer);;
  open_devs--;
}
 
int
MIDIbuf_write (int dev, struct fileinfo *file, const char *buf, int count)
{
  unsigned long   flags;
  int             c, n, i;
  unsigned char   tmp_data;
 
  dev = dev >> 4;
 
  if (!count)
    return 0;
 
  save_flags (flags);
  cli ();
 
  c = 0;
 
  while (c < count)
    {
      n = SPACE_AVAIL (midi_out_buf[dev]);
 
      if (n == 0)		/*
				 * No space just now. We have to sleep
				 */
	{
 
	  {
	    unsigned long   tlimit;
 
	    if (0)
	      current_set_timeout (tlimit = jiffies + (0));
	    else
	      tlimit = (unsigned long) -1;
	    midi_sleep_flag[dev].flags = WK_SLEEP;
	    module_interruptible_sleep_on (&midi_sleeper[dev]);
	    if (!(midi_sleep_flag[dev].flags & WK_WAKEUP))
	      {
		if (jiffies >= tlimit)
		  midi_sleep_flag[dev].flags |= WK_TIMEOUT;
	      }
	    midi_sleep_flag[dev].flags &= ~WK_SLEEP;
	  };
	  if (current_got_fatal_signal ())
	    {
	      restore_flags (flags);
	      return -(EINTR);
	    }
 
	  n = SPACE_AVAIL (midi_out_buf[dev]);
	}
 
      if (n > (count - c))
	n = count - c;
 
      for (i = 0; i < n; i++)
	{
	  memcpy_fromfs ((char *) &tmp_data, &(buf)[c], 1);
	  QUEUE_BYTE (midi_out_buf[dev], tmp_data);
	  c++;
	}
    }
 
  restore_flags (flags);
 
  return c;
}
 
 
int
MIDIbuf_read (int dev, struct fileinfo *file, char *buf, int count)
{
  int             n, c = 0;
  unsigned long   flags;
  unsigned char   tmp_data;
 
  dev = dev >> 4;
 
  save_flags (flags);
  cli ();
 
  if (!DATA_AVAIL (midi_in_buf[dev]))	/*
					 * No data yet, wait
					 */
    {
 
      {
	unsigned long   tlimit;
 
	if (parms[dev].prech_timeout)
	  current_set_timeout (tlimit = jiffies + (parms[dev].prech_timeout));
	else
	  tlimit = (unsigned long) -1;
	input_sleep_flag[dev].flags = WK_SLEEP;
	module_interruptible_sleep_on (&input_sleeper[dev]);
	if (!(input_sleep_flag[dev].flags & WK_WAKEUP))
	  {
	    if (jiffies >= tlimit)
	      input_sleep_flag[dev].flags |= WK_TIMEOUT;
	  }
	input_sleep_flag[dev].flags &= ~WK_SLEEP;
      };
      if (current_got_fatal_signal ())
	c = -(EINTR);		/*
				   * The user is getting restless
				 */
    }
 
  if (c == 0 && DATA_AVAIL (midi_in_buf[dev]))	/*
						 * Got some bytes
						 */
    {
      n = DATA_AVAIL (midi_in_buf[dev]);
      if (n > count)
	n = count;
      c = 0;
 
      while (c < n)
	{
	  REMOVE_BYTE (midi_in_buf[dev], tmp_data);
	  memcpy_tofs (&(buf)[c], (char *) &tmp_data, 1);
	  c++;
	}
    }
 
  restore_flags (flags);
 
  return c;
}
 
int
MIDIbuf_ioctl (int dev, struct fileinfo *file,
	       unsigned int cmd, caddr_t arg)
{
  int             val;
 
  dev = dev >> 4;
 
  if (((cmd >> 8) & 0xff) == 'C')
    {
      if (midi_devs[dev]->coproc)	/* Coprocessor ioctl */
	return midi_devs[dev]->coproc->ioctl (midi_devs[dev]->coproc->devc, cmd, arg, 0);
      else
	printk ("/dev/midi%d: No coprocessor for this device\n", dev);
 
      return -(ENXIO);
    }
  else
    switch (cmd)
      {
 
      case SNDCTL_MIDI_PRETIME:
	val = (int) get_user ((int *) arg);
	if (val < 0)
	  val = 0;
 
	val = (HZ * val) / 10;
	parms[dev].prech_timeout = val;
	return snd_ioctl_return ((int *) arg, val);
	break;
 
      default:
	return midi_devs[dev]->ioctl (dev, cmd, arg);
      }
}
 
int
MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
{
  dev = dev >> 4;
 
  switch (sel_type)
    {
    case SEL_IN:
      if (!DATA_AVAIL (midi_in_buf[dev]))
	{
 
	  input_sleep_flag[dev].flags = WK_SLEEP;
	  module_select_wait (&input_sleeper[dev], wait);
	  return 0;
	}
      return 1;
      break;
 
    case SEL_OUT:
      if (SPACE_AVAIL (midi_out_buf[dev]))
	{
 
	  midi_sleep_flag[dev].flags = WK_SLEEP;
	  module_select_wait (&midi_sleeper[dev], wait);
	  return 0;
	}
      return 1;
      break;
 
    case SEL_EX:
      return 0;
    }
 
  return 0;
}
 
 
void
MIDIbuf_init (void)
{
}
 
#endif
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.