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                                while (DATA_AVAIL(midi_out_buf[dev]))
 131                                {
 132                                        int ok;
 133                                        int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
 134
 135                                        spin_unlock_irqrestore(&lock,flags);/* Give some time to others */
 136                                        ok = midi_devs[dev]->outputc(dev, c);
 137                                        spin_lock_irqsave(&lock, flags);
 138                                        if (!ok)
 139                                                break;
 140                                        midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
 141                                        midi_out_buf[dev]->len--;
 142                                }
 143
 144                                if (DATA_AVAIL(midi_out_buf[dev]) < 100)
 145                                        wake_up(&midi_sleeper[dev]);
 146                        }
 147                poll_timer.expires = (1) + jiffies;
 148                add_timer(&poll_timer);
 149                /*
 150                 * Come back later
 151                 */
 152        }
 153        spin_unlock_irqrestore(&lock, flags);
 154}
 155
 156int MIDIbuf_open(int dev, struct file *file)
 157{
 158        int mode, err;
 159
 160        dev = dev >> 4;
 161        mode = translate_mode(file);
 162
 163        if (num_midis > MAX_MIDI_DEV)
 164        {
 165                printk(KERN_ERR "midi: Too many midi interfaces\n");
 166                num_midis = MAX_MIDI_DEV;
 167        }
 168        if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
 169                  return -ENXIO;
 170        /*
 171         *    Interrupts disabled. Be careful
 172         */
 173
 174        module_put(midi_devs[dev]->owner);
 175
 176        if ((err = midi_devs[dev]->open(dev, mode,
 177                                 midi_input_intr, midi_output_intr)) < 0)
 178                return err;
 179
 180        parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
 181        midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf));
 182
 183        if (midi_in_buf[dev] == NULL)
 184        {
 185                printk(KERN_WARNING "midi: Can't allocate buffer\n");
 186                midi_devs[dev]->close(dev);
 187                return -EIO;
 188        }
 189        midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
 190
 191        midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf));
 192
 193        if (midi_out_buf[dev] == NULL)
 194        {
 195                printk(KERN_WARNING "midi: Can't allocate buffer\n");
 196                midi_devs[dev]->close(dev);
 197                vfree(midi_in_buf[dev]);
 198                midi_in_buf[dev] = NULL;
 199                return -EIO;
 200        }
 201        midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
 202        open_devs++;
 203
 204        init_waitqueue_head(&midi_sleeper[dev]);
 205        init_waitqueue_head(&input_sleeper[dev]);
 206
 207        if (open_devs < 2)      /* This was first open */
 208        {
 209                poll_timer.expires = 1 + jiffies;
 210                add_timer(&poll_timer); /* Start polling */
 211        }
 212        return err;
 213}
 214
 215void MIDIbuf_release(int dev, struct file *file)
 216{
 217        int mode;
 218
 219        dev = dev >> 4;
 220        mode = translate_mode(file);
 221
 222        if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
 223                return;
 224
 225        /*
 226         * Wait until the queue is empty
 227         */
 228
 229        if (mode != OPEN_READ)
 230        {
 231                midi_devs[dev]->outputc(dev, 0xfe);     /*
 232                                                           * Active sensing to shut the
 233                                                           * devices
 234                                                         */
 235
 236                while (!signal_pending(current) && DATA_AVAIL(midi_out_buf[dev]))
 237                          interruptible_sleep_on(&midi_sleeper[dev]);
 238                /*
 239                 *      Sync
 240                 */
 241
 242                drain_midi_queue(dev);  /*
 243                                         * Ensure the output queues are empty
 244                                         */
 245        }
 246
 247        midi_devs[dev]->close(dev);
 248
 249        open_devs--;
 250        if (open_devs == 0)
 251                del_timer_sync(&poll_timer);
 252        vfree(midi_in_buf[dev]);
 253        vfree(midi_out_buf[dev]);
 254        midi_in_buf[dev] = NULL;
 255        midi_out_buf[dev] = NULL;
 256
 257        module_put(midi_devs[dev]->owner);
 258}
 259
 260int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count)
 261{
 262        int c, n, i;
 263        unsigned char tmp_data;
 264
 265        dev = dev >> 4;
 266
 267        if (!count)
 268                return 0;
 269
 270        c = 0;
 271
 272        while (c < count)
 273        {
 274                n = SPACE_AVAIL(midi_out_buf[dev]);
 275
 276                if (n == 0) {   /*
 277                                 * No space just now.
 278                                 */
 279
 280                        if (file->f_flags & O_NONBLOCK) {
 281                                c = -EAGAIN;
 282                                goto out;
 283                        }
 284
 285                        interruptible_sleep_on(&midi_sleeper[dev]);
 286                        if (signal_pending(current)) 
 287                        {
 288                                c = -EINTR;
 289                                goto out;
 290                        }
 291                        n = SPACE_AVAIL(midi_out_buf[dev]);
 292                }
 293                if (n > (count - c))
 294                        n = count - c;
 295
 296                for (i = 0; i < n; i++)
 297                {
 298                        /* BROKE BROKE BROKE - CAN'T DO THIS WITH CLI !! */
 299                        /* yes, think the same, so I removed the cli() brackets 
 300                                QUEUE_BYTE is protected against interrupts */
 301                        if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) {
 302                                c = -EFAULT;
 303                                goto out;
 304                        }
 305                        QUEUE_BYTE(midi_out_buf[dev], tmp_data);
 306                        c++;
 307                }
 308        }
 309out:
 310        return c;
 311}
 312
 313
 314int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count)
 315{
 316        int n, c = 0;
 317        unsigned char tmp_data;
 318
 319        dev = dev >> 4;
 320
 321        if (!DATA_AVAIL(midi_in_buf[dev])) {    /*
 322                                                 * No data yet, wait
 323                                                 */
 324                if (file->f_flags & O_NONBLOCK) {
 325                        c = -EAGAIN;
 326                        goto out;
 327                }
 328                interruptible_sleep_on_timeout(&input_sleeper[dev],
 329                                               parms[dev].prech_timeout);
 330
 331                if (signal_pending(current))
 332                        c = -EINTR;     /* The user is getting restless */
 333        }
 334        if (c == 0 && DATA_AVAIL(midi_in_buf[dev]))     /*
 335                                                         * Got some bytes
 336                                                         */
 337        {
 338                n = DATA_AVAIL(midi_in_buf[dev]);
 339                if (n > count)
 340                        n = count;
 341                c = 0;
 342
 343                while (c < n)
 344                {
 345                        char *fixit;
 346                        REMOVE_BYTE(midi_in_buf[dev], tmp_data);
 347                        fixit = (char *) &tmp_data;
 348                        /* BROKE BROKE BROKE */
 349                        /* yes removed the cli() brackets again
 350                         should q->len,tail&head be atomic_t? */
 351                        if (copy_to_user(&(buf)[c], fixit, 1)) {
 352                                c = -EFAULT;
 353                                goto out;
 354                        }
 355                        c++;
 356                }
 357        }
 358out:
 359        return c;
 360}
 361
 362int MIDIbuf_ioctl(int dev, struct file *file,
 363                  unsigned int cmd, void __user *arg)
 364{
 365        int val;
 366
 367        dev = dev >> 4;
 368        
 369        if (((cmd >> 8) & 0xff) == 'C') 
 370        {
 371                if (midi_devs[dev]->coproc)     /* Coprocessor ioctl */
 372                        return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
 373/*              printk("/dev/midi%d: No coprocessor for this device\n", dev);*/
 374                return -ENXIO;
 375        }
 376        else
 377        {
 378                switch (cmd) 
 379                {
 380                        case SNDCTL_MIDI_PRETIME:
 381                                if (get_user(val, (int __user *)arg))
 382                                        return -EFAULT;
 383                                if (val < 0)
 384                                        val = 0;
 385                                val = (HZ * val) / 10;
 386                                parms[dev].prech_timeout = val;
 387                                return put_user(val, (int __user *)arg);
 388                        
 389                        default:
 390                                if (!midi_devs[dev]->ioctl)
 391                                        return -EINVAL;
 392                                return midi_devs[dev]->ioctl(dev, cmd, arg);
 393                }
 394        }
 395}
 396
 397/* No kernel lock - fine */
 398unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait)
 399{
 400        unsigned int mask = 0;
 401
 402        dev = dev >> 4;
 403
 404        /* input */
 405        poll_wait(file, &input_sleeper[dev], wait);
 406        if (DATA_AVAIL(midi_in_buf[dev]))
 407                mask |= POLLIN | POLLRDNORM;
 408
 409        /* output */
 410        poll_wait(file, &midi_sleeper[dev], wait);
 411        if (!SPACE_AVAIL(midi_out_buf[dev]))
 412                mask |= POLLOUT | POLLWRNORM;
 413        
 414        return mask;
 415}
 416
 417
 418int MIDIbuf_avail(int dev)
 419{
 420        if (midi_in_buf[dev])
 421                return DATA_AVAIL (midi_in_buf[dev]);
 422        return 0;
 423}
 424EXPORT_SYMBOL(MIDIbuf_avail);
 425
 426
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.