MX6 processor family.
aboutsummaryrefslogblamecommitdiffstats
path: root/sound/oss/midibuf.c
blob: 8cdb2cfe65c841a7f942a25fde54b9d04e0d3ea6 (plain) (tree)
1
2
  
                      

















































                                                                               
                                                 











































































                                                                                       
                                                                     
                                 
                                               




                                                                                                          

                                                      








































                                                                                                                 
                                                            








                                                                                    
                                                             









































































































                                                                                       
                                                                           






















































































































                                                                                                        





                                                     

                             
/*
 * sound/oss/midibuf.c
 *
 * Device file manager for /dev/midi#
 */
/*
 * 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)
 */
#include <linux/stddef.h>
#include <linux/kmod.h>
#include <linux/spinlock.h>
#define MIDIBUF_C

#include "sound_config.h"


/*
 * Don't make MAX_QUEUE_SIZE larger than 4000
 */

#define MAX_QUEUE_SIZE	4000

static wait_queue_head_t midi_sleeper[MAX_MIDI_DEV];
static wait_queue_head_t input_sleeper[MAX_MIDI_DEV];

struct midi_buf
{
	int len, head, tail;
	unsigned char queue[MAX_QUEUE_SIZE];
};

struct midi_parms
{
	long 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 DEFINE_TIMER(poll_timer, midi_poll, 0, 0);

static volatile int open_devs;
static DEFINE_SPINLOCK(lock);

#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; \
	  spin_lock_irqsave(&lock, flags); \
	  q->queue[q->tail] = (data); \
	  q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
	  spin_unlock_irqrestore(&lock, flags); \
	}

#define REMOVE_BYTE(q, data) \
	if (DATA_AVAIL(q)) \
	{ \
	  unsigned long flags; \
	  spin_lock_irqsave(&lock, flags); \
	  data = q->queue[q->head]; \
	  q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
	  spin_unlock_irqrestore(&lock, flags); \
	}

static void drain_midi_queue(int dev)
{

	/*
	 * Give the Midi driver time to drain its output queues
	 */

	if (midi_devs[dev]->buffer_status != NULL)
		while (!signal_pending(current) && midi_devs[dev]->buffer_status(dev)) 
			interruptible_sleep_on_timeout(&midi_sleeper[dev],
						       HZ/10);
}

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);
		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;

	spin_lock_irqsave(&lock, flags);
	if (open_devs)
	{
		for (dev = 0; dev < num_midis; dev++)
			if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL)
			{
				while (DATA_AVAIL(midi_out_buf[dev]))
				{
					int ok;
					int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];

					spin_unlock_irqrestore(&lock,flags);/* Give some time to others */
					ok = midi_devs[dev]->outputc(dev, c);
					spin_lock_irqsave(&lock, flags);
					if (!ok)
						break;
					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)
					wake_up(&midi_sleeper[dev]);
			}
		poll_timer.expires = (1) + jiffies;
		add_timer(&poll_timer);
		/*
		 * Come back later
		 */
	}
	spin_unlock_irqrestore(&lock, flags);
}

int MIDIbuf_open(int dev, struct file *file)
{
	int mode, err;

	dev = dev >> 4;
	mode = translate_mode(file);

	if (num_midis > MAX_MIDI_DEV)
	{
		printk(KERN_ERR "midi: Too many midi interfaces\n");
		num_midis = MAX_MIDI_DEV;
	}
	if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
		  return -ENXIO;
	/*
	 *    Interrupts disabled. Be careful
	 */

	module_put(midi_devs[dev]->owner);

	if ((err = midi_devs[dev]->open(dev, mode,
				 midi_input_intr, midi_output_intr)) < 0)
		return err;

	parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
	midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf));

	if (midi_in_buf[dev] == NULL)
	{
		printk(KERN_WARNING "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;