seq_oss_readq.c (4692B)
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 */ 32struct seq_oss_readq * 33snd_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 */ 61void 62snd_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 */ 73void 74snd_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 */ 88int 89snd_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 */ 111struct readq_sysex_ctx { 112 struct seq_oss_readq *readq; 113 int dev; 114}; 115 116static 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 123int 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 */ 140int 141snd_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 */ 168int 169snd_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 */ 180void 181snd_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 */ 192void 193snd_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 */ 205unsigned int 206snd_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 */ 215int 216snd_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 */ 243void 244snd_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 */