123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- /*
- * 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)
- wait_event_interruptible_timeout(midi_sleeper[dev],
- !midi_devs[dev]->buffer_status(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;
- midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf));
- if (midi_out_buf[dev] == NULL)
- {
- printk(KERN_WARNING "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++;
- init_waitqueue_head(&midi_sleeper[dev]);
- init_waitqueue_head(&input_sleeper[dev]);
- 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 file *file)
- {
- int mode;
- dev = dev >> 4;
- mode = translate_mode(file);
- if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
- return;
- /*
- * Wait until the queue is empty
- */
- if (mode != OPEN_READ)
- {
- midi_devs[dev]->outputc(dev, 0xfe); /*
- * Active sensing to shut the
- * devices
- */
- wait_event_interruptible(midi_sleeper[dev],
- !DATA_AVAIL(midi_out_buf[dev]));
- /*
- * Sync
- */
- drain_midi_queue(dev); /*
- * Ensure the output queues are empty
- */
- }
- midi_devs[dev]->close(dev);
- open_devs--;
- if (open_devs == 0)
- del_timer_sync(&poll_timer);
- vfree(midi_in_buf[dev]);
- vfree(midi_out_buf[dev]);
- midi_in_buf[dev] = NULL;
- midi_out_buf[dev] = NULL;
- module_put(midi_devs[dev]->owner);
- }
- int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count)
- {
- int c, n, i;
- unsigned char tmp_data;
- dev = dev >> 4;
- if (!count)
- return 0;
- c = 0;
- while (c < count)
- {
- n = SPACE_AVAIL(midi_out_buf[dev]);
- if (n == 0) { /*
- * No space just now.
- */
- if (file->f_flags & O_NONBLOCK) {
- c = -EAGAIN;
- goto out;
- }
- if (wait_event_interruptible(midi_sleeper[dev],
- SPACE_AVAIL(midi_out_buf[dev])))
- {
- c = -EINTR;
- goto out;
- }
- n = SPACE_AVAIL(midi_out_buf[dev]);
- }
- if (n > (count - c))
- n = count - c;
- for (i = 0; i < n; i++)
- {
- /* BROKE BROKE BROKE - CAN'T DO THIS WITH CLI !! */
- /* yes, think the same, so I removed the cli() brackets
- QUEUE_BYTE is protected against interrupts */
- if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) {
- c = -EFAULT;
- goto out;
- }
- QUEUE_BYTE(midi_out_buf[dev], tmp_data);
- c++;
- }
- }
- out:
- return c;
- }
- int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count)
- {
- int n, c = 0;
- unsigned char tmp_data;
- dev = dev >> 4;
- if (!DATA_AVAIL(midi_in_buf[dev])) { /*
- * No data yet, wait
- */
- if (file->f_flags & O_NONBLOCK) {
- c = -EAGAIN;
- goto out;
- }
- wait_event_interruptible_timeout(input_sleeper[dev],
- DATA_AVAIL(midi_in_buf[dev]),
- parms[dev].prech_timeout);
- if (signal_pending(current))
- 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)
- {
- char *fixit;
- REMOVE_BYTE(midi_in_buf[dev], tmp_data);
- fixit = (char *) &tmp_data;
- /* BROKE BROKE BROKE */
- /* yes removed the cli() brackets again
- should q->len,tail&head be atomic_t? */
- if (copy_to_user(&(buf)[c], fixit, 1)) {
- c = -EFAULT;
- goto out;
- }
- c++;
- }
- }
- out:
- return c;
- }
- int MIDIbuf_ioctl(int dev, struct file *file,
- unsigned int cmd, void __user *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);
- /* printk("/dev/midi%d: No coprocessor for this device\n", dev);*/
- return -ENXIO;
- }
- else
- {
- switch (cmd)
- {
- case SNDCTL_MIDI_PRETIME:
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
- if (val < 0)
- val = 0;
- val = (HZ * val) / 10;
- parms[dev].prech_timeout = val;
- return put_user(val, (int __user *)arg);
-
- default:
- if (!midi_devs[dev]->ioctl)
- return -EINVAL;
- return midi_devs[dev]->ioctl(dev, cmd, arg);
- }
- }
- }
- /* No kernel lock - fine */
- unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait)
- {
- unsigned int mask = 0;
- dev = dev >> 4;
- /* input */
- poll_wait(file, &input_sleeper[dev], wait);
- if (DATA_AVAIL(midi_in_buf[dev]))
- mask |= POLLIN | POLLRDNORM;
- /* output */
- poll_wait(file, &midi_sleeper[dev], wait);
- if (!SPACE_AVAIL(midi_out_buf[dev]))
- mask |= POLLOUT | POLLWRNORM;
-
- return mask;
- }
- int MIDIbuf_avail(int dev)
- {
- if (midi_in_buf[dev])
- return DATA_AVAIL (midi_in_buf[dev]);
- return 0;
- }
- EXPORT_SYMBOL(MIDIbuf_avail);
|