~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/core/seq/oss/seq_oss_readq.c

Version: ~ [ linux-5.12-rc1 ] ~ [ linux-5.11.2 ] ~ [ linux-5.10.19 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.101 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.177 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.222 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.258 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.258 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 */
251 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp