Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * OSS compatible sequencer driver
0004  *
0005  * seq_oss_readq.c - MIDI input queue
0006  *
0007  * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
0008  */
0009 
0010 #include "seq_oss_readq.h"
0011 #include "seq_oss_event.h"
0012 #include <sound/seq_oss_legacy.h>
0013 #include "../seq_lock.h"
0014 #include <linux/wait.h>
0015 #include <linux/slab.h>
0016 
0017 /*
0018  * constants
0019  */
0020 //#define SNDRV_SEQ_OSS_MAX_TIMEOUT (unsigned long)(-1)
0021 #define SNDRV_SEQ_OSS_MAX_TIMEOUT   (HZ * 3600)
0022 
0023 
0024 /*
0025  * prototypes
0026  */
0027 
0028 
0029 /*
0030  * create a read queue
0031  */
0032 struct seq_oss_readq *
0033 snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen)
0034 {
0035     struct seq_oss_readq *q;
0036 
0037     q = kzalloc(sizeof(*q), GFP_KERNEL);
0038     if (!q)
0039         return NULL;
0040 
0041     q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL);
0042     if (!q->q) {
0043         kfree(q);
0044         return NULL;
0045     }
0046 
0047     q->maxlen = maxlen;
0048     q->qlen = 0;
0049     q->head = q->tail = 0;
0050     init_waitqueue_head(&q->midi_sleep);
0051     spin_lock_init(&q->lock);
0052     q->pre_event_timeout = SNDRV_SEQ_OSS_MAX_TIMEOUT;
0053     q->input_time = (unsigned long)-1;
0054 
0055     return q;
0056 }
0057 
0058 /*
0059  * delete the read queue
0060  */
0061 void
0062 snd_seq_oss_readq_delete(struct seq_oss_readq *q)
0063 {
0064     if (q) {
0065         kfree(q->q);
0066         kfree(q);
0067     }
0068 }
0069 
0070 /*
0071  * reset the read queue
0072  */
0073 void
0074 snd_seq_oss_readq_clear(struct seq_oss_readq *q)
0075 {
0076     if (q->qlen) {
0077         q->qlen = 0;
0078         q->head = q->tail = 0;
0079     }
0080     /* if someone sleeping, wake'em up */
0081     wake_up(&q->midi_sleep);
0082     q->input_time = (unsigned long)-1;
0083 }
0084 
0085 /*
0086  * put a midi byte
0087  */
0088 int
0089 snd_seq_oss_readq_puts(struct seq_oss_readq *q, int dev, unsigned char *data, int len)
0090 {
0091     union evrec rec;
0092     int result;
0093 
0094     memset(&rec, 0, sizeof(rec));
0095     rec.c[0] = SEQ_MIDIPUTC;
0096     rec.c[2] = dev;
0097 
0098     while (len-- > 0) {
0099         rec.c[1] = *data++;
0100         result = snd_seq_oss_readq_put_event(q, &rec);
0101         if (result < 0)
0102             return result;
0103     }
0104     return 0;
0105 }
0106 
0107 /*
0108  * put MIDI sysex bytes; the event buffer may be chained, thus it has
0109  * to be expanded via snd_seq_dump_var_event().
0110  */
0111 struct readq_sysex_ctx {
0112     struct seq_oss_readq *readq;
0113     int dev;
0114 };
0115 
0116 static int readq_dump_sysex(void *ptr, void *buf, int count)
0117 {
0118     struct readq_sysex_ctx *ctx = ptr;
0119 
0120     return snd_seq_oss_readq_puts(ctx->readq, ctx->dev, buf, count);
0121 }
0122 
0123 int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,
0124                 struct snd_seq_event *ev)
0125 {
0126     struct readq_sysex_ctx ctx = {
0127         .readq = q,
0128         .dev = dev
0129     };
0130 
0131     if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
0132         return 0;
0133     return snd_seq_dump_var_event(ev, readq_dump_sysex, &ctx);
0134 }
0135 
0136 /*
0137  * copy an event to input queue:
0138  * return zero if enqueued
0139  */
0140 int
0141 snd_seq_oss_readq_put_event(struct seq_oss_readq *q, union evrec *ev)
0142 {
0143     unsigned long flags;
0144 
0145     spin_lock_irqsave(&q->lock, flags);
0146     if (q->qlen >= q->maxlen - 1) {
0147         spin_unlock_irqrestore(&q->lock, flags);
0148         return -ENOMEM;
0149     }
0150 
0151     memcpy(&q->q[q->tail], ev, sizeof(*ev));
0152     q->tail = (q->tail + 1) % q->maxlen;
0153     q->qlen++;
0154 
0155     /* wake up sleeper */
0156     wake_up(&q->midi_sleep);
0157 
0158     spin_unlock_irqrestore(&q->lock, flags);
0159 
0160     return 0;
0161 }
0162 
0163 
0164 /*
0165  * pop queue
0166  * caller must hold lock
0167  */
0168 int
0169 snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec)
0170 {
0171     if (q->qlen == 0)
0172         return -EAGAIN;
0173     memcpy(rec, &q->q[q->head], sizeof(*rec));
0174     return 0;
0175 }
0176 
0177 /*
0178  * sleep until ready
0179  */
0180 void
0181 snd_seq_oss_readq_wait(struct seq_oss_readq *q)
0182 {
0183     wait_event_interruptible_timeout(q->midi_sleep,
0184                      (q->qlen > 0 || q->head == q->tail),
0185                      q->pre_event_timeout);
0186 }
0187 
0188 /*
0189  * drain one record
0190  * caller must hold lock
0191  */
0192 void
0193 snd_seq_oss_readq_free(struct seq_oss_readq *q)
0194 {
0195     if (q->qlen > 0) {
0196         q->head = (q->head + 1) % q->maxlen;
0197         q->qlen--;
0198     }
0199 }
0200 
0201 /*
0202  * polling/select:
0203  * return non-zero if readq is not empty.
0204  */
0205 unsigned int
0206 snd_seq_oss_readq_poll(struct seq_oss_readq *q, struct file *file, poll_table *wait)
0207 {
0208     poll_wait(file, &q->midi_sleep, wait);
0209     return q->qlen;
0210 }
0211 
0212 /*
0213  * put a timestamp
0214  */
0215 int
0216 snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *q, unsigned long curt, int seq_mode)
0217 {
0218     if (curt != q->input_time) {
0219         union evrec rec;
0220         memset(&rec, 0, sizeof(rec));
0221         switch (seq_mode) {
0222         case SNDRV_SEQ_OSS_MODE_SYNTH:
0223             rec.echo = (curt << 8) | SEQ_WAIT;
0224             snd_seq_oss_readq_put_event(q, &rec);
0225             break;
0226         case SNDRV_SEQ_OSS_MODE_MUSIC:
0227             rec.t.code = EV_TIMING;
0228             rec.t.cmd = TMR_WAIT_ABS;
0229             rec.t.time = curt;
0230             snd_seq_oss_readq_put_event(q, &rec);
0231             break;
0232         }
0233         q->input_time = curt;
0234     }
0235     return 0;
0236 }
0237 
0238 
0239 #ifdef CONFIG_SND_PROC_FS
0240 /*
0241  * proc interface
0242  */
0243 void
0244 snd_seq_oss_readq_info_read(struct seq_oss_readq *q, struct snd_info_buffer *buf)
0245 {
0246     snd_iprintf(buf, "  read queue [%s] length = %d : tick = %ld\n",
0247             (waitqueue_active(&q->midi_sleep) ? "sleeping":"running"),
0248             q->qlen, q->input_time);
0249 }
0250 #endif /* CONFIG_SND_PROC_FS */