cregit-Linux how code gets into the kernel

Release 4.7 sound/oss/midibuf.c

Directory: sound/oss
/*
 * 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); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3784.09%685.71%
arnd bergmannarnd bergmann715.91%114.29%
Total44100.00%7100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git63100.00%3100.00%
Total63100.00%3100.00%


static void midi_output_intr(int dev) { /* * Currently NOP */ }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git10100.00%2100.00%
Total10100.00%2100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git17886.41%571.43%
peter waechtlerpeter waechtler199.22%114.29%
clemens ladischclemens ladisch94.37%114.29%
Total206100.00%7100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git31599.68%1090.91%
christoph hellwigchristoph hellwig10.32%19.09%
Total316100.00%11100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git13585.44%975.00%
linus torvaldslinus torvalds159.49%18.33%
arnd bergmannarnd bergmann74.43%18.33%
christoph hellwigchristoph hellwig10.63%18.33%
Total158100.00%12100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git17882.03%964.29%
arnaldo carvalho de meloarnaldo carvalho de melo2611.98%17.14%
arnd bergmannarnd bergmann104.61%17.14%
lucas de marchilucas de marchi10.46%17.14%
al viroal viro10.46%17.14%
peter waechtlerpeter waechtler10.46%17.14%
Total217100.00%14100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git18485.58%1275.00%
arnaldo carvalho de meloarnaldo carvalho de melo209.30%16.25%
arnd bergmannarnd bergmann94.19%16.25%
al viroal viro10.47%16.25%
peter waechtlerpeter waechtler10.47%16.25%
Total215100.00%16100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git18597.37%990.00%
al viroal viro52.63%110.00%
Total190100.00%10100.00%

/* 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; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git94100.00%6100.00%
Total94100.00%6100.00%


int MIDIbuf_avail(int dev) { if (midi_in_buf[dev]) return DATA_AVAIL (midi_in_buf[dev]); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git27100.00%2100.00%
Total27100.00%2100.00%

EXPORT_SYMBOL(MIDIbuf_avail);

Overall Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git155090.59%2767.50%
arnaldo carvalho de meloarnaldo carvalho de melo462.69%12.50%
arnd bergmannarnd bergmann331.93%12.50%
peter waechtlerpeter waechtler281.64%12.50%
linus torvaldslinus torvalds150.88%12.50%
clemens ladischclemens ladisch90.53%12.50%
al viroal viro70.41%12.50%
andrew mortonandrew morton60.35%12.50%
adrian bunkadrian bunk50.29%12.50%
thomas gleixnerthomas gleixner40.23%12.50%
ingo molnaringo molnar40.23%12.50%
christoph hellwigchristoph hellwig20.12%12.50%
uwe zeisbergeruwe zeisberger10.06%12.50%
lucas de marchilucas de marchi10.06%12.50%
Total1711100.00%40100.00%
Directory: sound/oss
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}