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