root/sound/core/seq/oss/seq_oss_readq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_seq_oss_readq_new
  2. snd_seq_oss_readq_delete
  3. snd_seq_oss_readq_clear
  4. snd_seq_oss_readq_puts
  5. readq_dump_sysex
  6. snd_seq_oss_readq_sysex
  7. snd_seq_oss_readq_put_event
  8. snd_seq_oss_readq_pick
  9. snd_seq_oss_readq_wait
  10. snd_seq_oss_readq_free
  11. snd_seq_oss_readq_poll
  12. snd_seq_oss_readq_put_timestamp
  13. snd_seq_oss_readq_info_read

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * OSS compatible sequencer driver
   4  *
   5  * seq_oss_readq.c - MIDI input queue
   6  *
   7  * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
   8  */
   9 
  10 #include "seq_oss_readq.h"
  11 #include "seq_oss_event.h"
  12 #include <sound/seq_oss_legacy.h>
  13 #include "../seq_lock.h"
  14 #include <linux/wait.h>
  15 #include <linux/slab.h>
  16 
  17 /*
  18  * constants
  19  */
  20 //#define SNDRV_SEQ_OSS_MAX_TIMEOUT     (unsigned long)(-1)
  21 #define SNDRV_SEQ_OSS_MAX_TIMEOUT       (HZ * 3600)
  22 
  23 
  24 /*
  25  * prototypes
  26  */
  27 
  28 
  29 /*
  30  * create a read queue
  31  */
  32 struct seq_oss_readq *
  33 snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen)
  34 {
  35         struct seq_oss_readq *q;
  36 
  37         q = kzalloc(sizeof(*q), GFP_KERNEL);
  38         if (!q)
  39                 return NULL;
  40 
  41         q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL);
  42         if (!q->q) {
  43                 kfree(q);
  44                 return NULL;
  45         }
  46 
  47         q->maxlen = maxlen;
  48         q->qlen = 0;
  49         q->head = q->tail = 0;
  50         init_waitqueue_head(&q->midi_sleep);
  51         spin_lock_init(&q->lock);
  52         q->pre_event_timeout = SNDRV_SEQ_OSS_MAX_TIMEOUT;
  53         q->input_time = (unsigned long)-1;
  54 
  55         return q;
  56 }
  57 
  58 /*
  59  * delete the read queue
  60  */
  61 void
  62 snd_seq_oss_readq_delete(struct seq_oss_readq *q)
  63 {
  64         if (q) {
  65                 kfree(q->q);
  66                 kfree(q);
  67         }
  68 }
  69 
  70 /*
  71  * reset the read queue
  72  */
  73 void
  74 snd_seq_oss_readq_clear(struct seq_oss_readq *q)
  75 {
  76         if (q->qlen) {
  77                 q->qlen = 0;
  78                 q->head = q->tail = 0;
  79         }
  80         /* if someone sleeping, wake'em up */
  81         wake_up(&q->midi_sleep);
  82         q->input_time = (unsigned long)-1;
  83 }
  84 
  85 /*
  86  * put a midi byte
  87  */
  88 int
  89 snd_seq_oss_readq_puts(struct seq_oss_readq *q, int dev, unsigned char *data, int len)
  90 {
  91         union evrec rec;
  92         int result;
  93 
  94         memset(&rec, 0, sizeof(rec));
  95         rec.c[0] = SEQ_MIDIPUTC;
  96         rec.c[2] = dev;
  97 
  98         while (len-- > 0) {
  99                 rec.c[1] = *data++;
 100                 result = snd_seq_oss_readq_put_event(q, &rec);
 101                 if (result < 0)
 102                         return result;
 103         }
 104         return 0;
 105 }
 106 
 107 /*
 108  * put MIDI sysex bytes; the event buffer may be chained, thus it has
 109  * to be expanded via snd_seq_dump_var_event().
 110  */
 111 struct readq_sysex_ctx {
 112         struct seq_oss_readq *readq;
 113         int dev;
 114 };
 115 
 116 static int readq_dump_sysex(void *ptr, void *buf, int count)
 117 {
 118         struct readq_sysex_ctx *ctx = ptr;
 119 
 120         return snd_seq_oss_readq_puts(ctx->readq, ctx->dev, buf, count);
 121 }
 122 
 123 int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,
 124                             struct snd_seq_event *ev)
 125 {
 126         struct readq_sysex_ctx ctx = {
 127                 .readq = q,
 128                 .dev = dev
 129         };
 130 
 131         if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
 132                 return 0;
 133         return snd_seq_dump_var_event(ev, readq_dump_sysex, &ctx);
 134 }
 135 
 136 /*
 137  * copy an event to input queue:
 138  * return zero if enqueued
 139  */
 140 int
 141 snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
 142 {
 143         unsigned long flags;
 144 
 145         spin_lock_irqsave(&q->lock, flags);
 146         if (q->qlen >= q->maxlen - 1) {
 147                 spin_unlock_irqrestore(&q->lock, flags);
 148                 return -ENOMEM;
 149         }
 150 
 151         memcpy(&q->q[q->tail], ev, sizeof(*ev));
 152         q->tail = (q->tail + 1) % q->maxlen;
 153         q->qlen++;
 154 
 155         /* wake up sleeper */
 156         wake_up(&q->midi_sleep);
 157 
 158         spin_unlock_irqrestore(&q->lock, flags);
 159 
 160         return 0;
 161 }
 162 
 163 
 164 /*
 165  * pop queue
 166  * caller must hold lock
 167  */
 168 int
 169 snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec)
 170 {
 171         if (q->qlen == 0)
 172                 return -EAGAIN;
 173         memcpy(rec, &q->q[q->head], sizeof(*rec));
 174         return 0;
 175 }
 176 
 177 /*
 178  * sleep until ready
 179  */
 180 void
 181 snd_seq_oss_readq_wait(struct seq_oss_readq *q)
 182 {
 183         wait_event_interruptible_timeout(q->midi_sleep,
 184                                          (q->qlen > 0 || q->head == q->tail),
 185                                          q->pre_event_timeout);
 186 }
 187 
 188 /*
 189  * drain one record
 190  * caller must hold lock
 191  */
 192 void
 193 snd_seq_oss_readq_free(struct seq_oss_readq *q)
 194 {
 195         if (q->qlen > 0) {
 196                 q->head = (q->head + 1) % q->maxlen;
 197                 q->qlen--;
 198         }
 199 }
 200 
 201 /*
 202  * polling/select:
 203  * return non-zero if readq is not empty.
 204  */
 205 unsigned int
 206 snd_seq_oss_readq_poll(struct seq_oss_readq *q, struct file *file, poll_table *wait)
 207 {
 208         poll_wait(file, &q->midi_sleep, wait);
 209         return q->qlen;
 210 }
 211 
 212 /*
 213  * put a timestamp
 214  */
 215 int
 216 snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *q, unsigned long curt, int seq_mode)
 217 {
 218         if (curt != q->input_time) {
 219                 union evrec rec;
 220                 memset(&rec, 0, sizeof(rec));
 221                 switch (seq_mode) {
 222                 case SNDRV_SEQ_OSS_MODE_SYNTH:
 223                         rec.echo = (curt << 8) | SEQ_WAIT;
 224                         snd_seq_oss_readq_put_event(q, &rec);
 225                         break;
 226                 case SNDRV_SEQ_OSS_MODE_MUSIC:
 227                         rec.t.code = EV_TIMING;
 228                         rec.t.cmd = TMR_WAIT_ABS;
 229                         rec.t.time = curt;
 230                         snd_seq_oss_readq_put_event(q, &rec);
 231                         break;
 232                 }
 233                 q->input_time = curt;
 234         }
 235         return 0;
 236 }
 237 
 238 
 239 #ifdef CONFIG_SND_PROC_FS
 240 /*
 241  * proc interface
 242  */
 243 void
 244 snd_seq_oss_readq_info_read(struct seq_oss_readq *q, struct snd_info_buffer *buf)
 245 {
 246         snd_iprintf(buf, "  read queue [%s] length = %d : tick = %ld\n",
 247                     (waitqueue_active(&q->midi_sleep) ? "sleeping":"running"),
 248                     q->qlen, q->input_time);
 249 }
 250 #endif /* CONFIG_SND_PROC_FS */

/* [<][>][^][v][top][bottom][index][help] */