Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 244 lines 4.5 kB view raw
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_obj(*q); 38 if (!q) 39 return NULL; 40 41 q->q = kzalloc_objs(union evrec, maxlen); 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 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 */ 162int 163snd_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 */ 174void 175snd_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 */ 186void 187snd_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 */ 199unsigned int 200snd_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 */ 209int 210snd_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 */ 237void 238snd_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 */