linux/sound/oss/midibuf.c
<<
>>
Prefs
   1/*
   2 * sound/oss/midibuf.c
   3 *
   4 * Device file manager for /dev/midi#
   5 */
   6/*
   7 * Copyright (C) by Hannu Savolainen 1993-1997
   8 *
   9 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  10 * Version 2 (June 1991). See the "COPYING" file distributed with this software
  11 * for more info.
  12 */
  13/*
  14 * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
  15 */
  16#include <linux/stddef.h>
  17#include <linux/kmod.h>
  18#include <linux/spinlock.h>
  19#define MIDIBUF_C
  20
  21#include "sound_config.h"
  22
  23
  24/*
  25 * Don't make MAX_QUEUE_SIZE larger than 4000
  26 */
  27
  28#define MAX_QUEUE_SIZE  4000
  29
  30static wait_queue_head_t midi_sleeper[MAX_MIDI_DEV];
  31static wait_queue_head_t input_sleeper[MAX_MIDI_DEV];
  32
  33struct midi_buf
  34{
  35        int len, head, tail;
  36        unsigned char queue[MAX_QUEUE_SIZE];
  37};
  38
  39struct midi_parms
  40{
  41        long prech_timeout;     /*
  42                                 * Timeout before the first ch
  43                                 */
  44};
  45
  46static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL};
  47static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL};
  48static struct midi_parms parms[MAX_MIDI_DEV];
  49
  50static void midi_poll(unsigned long dummy);
  51
  52
  53static DEFINE_TIMER(poll_timer, midi_poll, 0, 0);
  54
  55static volatile int open_devs;
  56static DEFINE_SPINLOCK(lock);
  57
  58#define DATA_AVAIL(q) (q->len)
  59#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)
  60
  61#define QUEUE_BYTE(q, data) \
  62        if (SPACE_AVAIL(q)) \
  63        { \
  64          unsigned long flags; \
  65          spin_lock_irqsave(&lock, flags); \
  66          q->queue[q->tail] = (data); \
  67          q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
  68          spin_unlock_irqrestore(&lock, flags); \
  69        }
  70
  71#define REMOVE_BYTE(q, data) \
  72        if (DATA_AVAIL(q)) \
  73        { \
  74          unsigned long flags; \
  75          spin_lock_irqsave(&lock, flags); \
  76          data = q->queue[q->head]; \
  77          q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
  78          spin_unlock_irqrestore(&lock, flags); \
  79        }
  80
  81static void drain_midi_queue(int dev)
  82{
  83
  84        /*
  85         * Give the Midi driver time to drain its output queues
  86         */
  87
  88        if (midi_devs[dev]->buffer_status != NULL)
  89                while (!signal_pending(current) && midi_devs[dev]->buffer_status(dev)) 
  90                        interruptible_sleep_on_timeout(&midi_sleeper[dev],
  91                                                       HZ/10);
  92}
  93
  94static void midi_input_intr(int dev, unsigned char data)
  95{
  96        if (midi_in_buf[dev] == NULL)
  97                return;
  98
  99        if (data == 0xfe)       /*
 100                                 * Active sensing
 101                                 */
 102                return;         /*
 103                                 * Ignore
 104                                 */
 105
 106        if (SPACE_AVAIL(midi_in_buf[dev])) {
 107                QUEUE_BYTE(midi_in_buf[dev], data);
 108                wake_up(&input_sleeper[dev]);
 109        }
 110}
 111
 112static void midi_output_intr(int dev)
 113{
 114        /*
 115         * Currently NOP
 116         */
 117}
 118
 119static void midi_poll(unsigned long dummy)
 120{
 121        unsigned long   flags;
 122        int             dev;
 123
 124        spin_lock_irqsave(&lock, flags);
 125        if (open_devs)
 126        {
 127                for (dev = 0; dev < num_midis; dev++)
 128                        if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL)
 129                        {
 130                                int ok = 1;
 131
 132                                while (DATA_AVAIL(midi_out_buf[dev]) && ok)
 133                                {
 134                                        int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
 135
 136                                        spin_unlock_irqrestore(&lock,flags);/* Give some time to others */
 137                                        ok = midi_devs[dev]->outputc(dev, c);
 138                                        spin_lock_irqsave(&lock, flags);
 139                                        midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
 140                                        midi_out_buf[dev]->len--;
 141                                }
 142
 143                                if (DATA_AVAIL(midi_out_buf[dev]) < 100)
 144                                        wake_up(&midi_sleeper[dev]);
 145                        }
 146                poll_timer.expires = (1) + jiffies;
 147                add_timer(&poll_timer);
 148                /*
 149                 * Come back later
 150                 */
 151        }
 152        spin_unlock_irqrestore(&lock, flags);
 153}
 154
 155int MIDIbuf_open(int dev, struct file *file)
 156{
 157        int mode, err;
 158
 159        dev = dev >> 4;
 160        mode = translate_mode(file);
 161
 162        if (num_midis > MAX_MIDI_DEV)
 163        {
 164                printk(KERN_ERR "midi: Too many midi interfaces\n");
 165                num_midis = MAX_MIDI_DEV;
 166        }
 167        if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
 168                  return -ENXIO;
 169        /*
 170         *    Interrupts disabled. Be careful
 171         */
 172
 173        module_put(midi_devs[dev]->owner);
 174
 175        if ((err = midi_devs[dev]->open(dev, mode,
 176                                 midi_input_intr, midi_output_intr)) < 0)
 177                return err;
 178
 179        parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
 180        midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
 181
 182        if (midi_in_buf[dev] == NULL)
 183        {
 184                printk(KERN_WARNING "midi: Can't allocate buffer\n");
 185                midi_devs[dev]->close(dev);
 186                return -EIO;
 187        }
 188        midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
 189
 190        midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
 191
 192        if (midi_out_buf[dev] == NULL)
 193        {
 194                printk(KERN_WARNING "midi: Can't allocate buffer\n");
 195                midi_devs[dev]->close(dev);
 196                vfree(midi_in_buf[dev]);
 197                midi_in_buf[dev] = NULL;
 198                return -EIO;
 199        }
 200        midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
 201        open_devs++;
 202
 203        init_waitqueue_head(&midi_sleeper[dev]);
 204        init_waitqueue_head(&input_sleeper[dev]);
 205
 206        if (open_devs < 2)      /* This was first open */
 207        {
 208                poll_timer.expires = 1 + jiffies;
 209                add_timer(&poll_timer); /* Start polling */
 210        }
 211        return err;
 212}
 213
 214void MIDIbuf_release(int dev, struct file *file)
 215{
 216        int mode;
 217
 218        dev = dev >> 4;
 219        mode = translate_mode(file);
 220
 221        if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
 222                return;
 223
 224        /*
 225         * Wait until the queue is empty
 226         */
 227
 228        if (mode != OPEN_READ)
 229        {
 230                midi_devs[dev]->outputc(dev, 0xfe);     /*
 231                                                           * Active sensing to shut the
 232                                                           * devices
 233                                                         */
 234
 235                while (!signal_pending(current) && DATA_AVAIL(midi_out_buf[dev]))
 236                          interruptible_sleep_on(&midi_sleeper[dev]);
 237                /*
 238                 *      Sync
 239                 */
 240
 241                drain_midi_queue(dev);  /*
 242                                         * Ensure the output queues are empty
 243                                         */
 244        }
 245
 246        midi_devs[dev]->close(dev);
 247
 248        open_devs--;
 249        if (open_devs == 0)
 250                del_timer_sync(&poll_timer);
 251        vfree(midi_in_buf[dev]);
 252        vfree(midi_out_buf[dev]);
 253        midi_in_buf[dev] = NULL;
 254        midi_out_buf[dev] = NULL;
 255
 256        module_put(midi_devs[dev]->owner);
 257}
 258
 259int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count)
 260{
 261        int c, n, i;
 262        unsigned char tmp_data;
 263
 264        dev = dev >> 4;
 265
 266        if (!count)
 267                return 0;
 268
 269        c = 0;
 270
 271        while (c < count)
 272        {
 273                n = SPACE_AVAIL(midi_out_buf[dev]);
 274
 275                if (n == 0) {   /*
 276                                 * No space just now.
 277                                 */
 278
 279                        if (file->f_flags & O_NONBLOCK) {
 280                                c = -EAGAIN;
 281                                goto out;
 282                        }
 283
 284                        interruptible_sleep_on(&midi_sleeper[dev]);
 285                        if (signal_pending(current)) 
 286                        {
 287                                c = -EINTR;
 288                                goto out;
 289                        }
 290                        n = SPACE_AVAIL(midi_out_buf[dev]);
 291                }
 292                if (n > (count - c))
 293                        n = count - c;
 294
 295                for (i = 0; i < n; i++)
 296                {
 297                        /* BROKE BROKE BROKE - CANT DO THIS WITH CLI !! */
 298                        /* yes, think the same, so I removed the cli() brackets 
 299                                QUEUE_BYTE is protected against interrupts */
 300                        if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) {
 301                                c = -EFAULT;
 302                                goto out;
 303                        }
 304                        QUEUE_BYTE(midi_out_buf[dev], tmp_data);
 305                        c++;
 306                }
 307        }
 308out:
 309        return c;
 310}
 311
 312
 313int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count)
 314{
 315        int n, c = 0;
 316        unsigned char tmp_data;
 317
 318        dev = dev >> 4;
 319
 320        if (!DATA_AVAIL(midi_in_buf[dev])) {    /*
 321                                                 * No data yet, wait
 322                                                 */
 323                if (file->f_flags & O_NONBLOCK) {
 324                        c = -EAGAIN;
 325                        goto out;
 326                }
 327                interruptible_sleep_on_timeout(&input_sleeper[dev],
 328                                               parms[dev].prech_timeout);
 329
 330                if (signal_pending(current))
 331                        c = -EINTR;     /* The user is getting restless */
 332        }
 333        if (c == 0 && DATA_AVAIL(midi_in_buf[dev]))     /*
 334                                                         * Got some bytes
 335                                                         */
 336        {
 337                n = DATA_AVAIL(midi_in_buf[dev]);
 338                if (n > count)
 339                        n = count;
 340                c = 0;
 341
 342                while (c < n)
 343                {
 344                        char *fixit;
 345                        REMOVE_BYTE(midi_in_buf[dev], tmp_data);
 346                        fixit = (char *) &tmp_data;
 347                        /* BROKE BROKE BROKE */
 348                        /* yes removed the cli() brackets again
 349                         should q->len,tail&head be atomic_t? */
 350                        if (copy_to_user(&(buf)[c], fixit, 1)) {
 351                                c = -EFAULT;
 352                                goto out;
 353                        }
 354                        c++;
 355                }
 356        }
 357out:
 358        return c;
 359}
 360
 361int MIDIbuf_ioctl(int dev, struct file *file,
 362                  unsigned int cmd, void __user *arg)
 363{
 364        int val;
 365
 366        dev = dev >> 4;
 367        
 368        if (((cmd >> 8) & 0xff) == 'C') 
 369        {
 370                if (midi_devs[dev]->coproc)     /* Coprocessor ioctl */
 371                        return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
 372/*              printk("/dev/midi%d: No coprocessor for this device\n", dev);*/
 373                return -ENXIO;
 374        }
 375        else
 376        {
 377                switch (cmd) 
 378                {
 379                        case SNDCTL_MIDI_PRETIME:
 380                                if (get_user(val, (int __user *)arg))
 381                                        return -EFAULT;
 382                                if (val < 0)
 383                                        val = 0;
 384                                val = (HZ * val) / 10;
 385                                parms[dev].prech_timeout = val;
 386                                return put_user(val, (int __user *)arg);
 387                        
 388                        default:
 389                                if (!midi_devs[dev]->ioctl)
 390                                        return -EINVAL;
 391                                return midi_devs[dev]->ioctl(dev, cmd, arg);
 392                }
 393        }
 394}
 395
 396/* No kernel lock - fine */
 397unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait)
 398{
 399        unsigned int mask = 0;
 400
 401        dev = dev >> 4;
 402
 403        /* input */
 404        poll_wait(file, &input_sleeper[dev], wait);
 405        if (DATA_AVAIL(midi_in_buf[dev]))
 406                mask |= POLLIN | POLLRDNORM;
 407
 408        /* output */
 409        poll_wait(file, &midi_sleeper[dev], wait);
 410        if (!SPACE_AVAIL(midi_out_buf[dev]))
 411                mask |= POLLOUT | POLLWRNORM;
 412        
 413        return mask;
 414}
 415
 416
 417int MIDIbuf_avail(int dev)
 418{
 419        if (midi_in_buf[dev])
 420                return DATA_AVAIL (midi_in_buf[dev]);
 421        return 0;
 422}
 423EXPORT_SYMBOL(MIDIbuf_avail);
 424
 425