cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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