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 guard(spinlock_irqsave)(&q->lock); 144 if (q->qlen >= q->maxlen - 1) 145 return -ENOMEM; 146 147 memcpy(&q->q[q->tail], ev, sizeof(*ev)); 148 q->tail = (q->tail + 1) % q->maxlen; 149 q->qlen++; 150 151 /* wake up sleeper */ 152 wake_up(&q->midi_sleep); 153 154 return 0; 155 } 156 157 158 /* 159 * pop queue 160 * caller must hold lock 161 */ 162 int 163 snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec) 164 { 165 if (q->qlen == 0) 166 return -EAGAIN; 167 memcpy(rec, &q->q[q->head], sizeof(*rec)); 168 return 0; 169 } 170 171 /* 172 * sleep until ready 173 */ 174 void 175 snd_seq_oss_readq_wait(struct seq_oss_readq *q) 176 { 177 wait_event_interruptible_timeout(q->midi_sleep, 178 (q->qlen > 0 || q->head == q->tail), 179 q->pre_event_timeout); 180 } 181 182 /* 183 * drain one record 184 * caller must hold lock 185 */ 186 void 187 snd_seq_oss_readq_free(struct seq_oss_readq *q) 188 { 189 if (q->qlen > 0) { 190 q->head = (q->head + 1) % q->maxlen; 191 q->qlen--; 192 } 193 } 194 195 /* 196 * polling/select: 197 * return non-zero if readq is not empty. 198 */ 199 unsigned int 200 snd_seq_oss_readq_poll(struct seq_oss_readq *q, struct file *file, poll_table *wait) 201 { 202 poll_wait(file, &q->midi_sleep, wait); 203 return q->qlen; 204 } 205 206 /* 207 * put a timestamp 208 */ 209 int 210 snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *q, unsigned long curt, int seq_mode) 211 { 212 if (curt != q->input_time) { 213 union evrec rec; 214 memset(&rec, 0, sizeof(rec)); 215 switch (seq_mode) { 216 case SNDRV_SEQ_OSS_MODE_SYNTH: 217 rec.echo = (curt << 8) | SEQ_WAIT; 218 snd_seq_oss_readq_put_event(q, &rec); 219 break; 220 case SNDRV_SEQ_OSS_MODE_MUSIC: 221 rec.t.code = EV_TIMING; 222 rec.t.cmd = TMR_WAIT_ABS; 223 rec.t.time = curt; 224 snd_seq_oss_readq_put_event(q, &rec); 225 break; 226 } 227 q->input_time = curt; 228 } 229 return 0; 230 } 231 232 233 #ifdef CONFIG_SND_PROC_FS 234 /* 235 * proc interface 236 */ 237 void 238 snd_seq_oss_readq_info_read(struct seq_oss_readq *q, struct snd_info_buffer *buf) 239 { 240 snd_iprintf(buf, " read queue [%s] length = %d : tick = %ld\n", 241 (waitqueue_active(&q->midi_sleep) ? "sleeping":"running"), 242 q->qlen, q->input_time); 243 } 244 #endif /* CONFIG_SND_PROC_FS */ 245